Springboot学习笔记

嗯,加油生活,依旧,摘几句子.
        
我十有八九的欲言又止,在日后想来都庆幸。而绝大多数的敞开心扉在事后都追悔。   -------德卡先生的信箱2019.10.3

 


前后端分离介绍:

  • 前后端不分:
    • 后端模板:jsp,freemarker
    • 前端模板:thyeleaf
  • 当应用于多个移动端时,需要前后端分离。
  • 前后端分离后,后端不在写页面,只提供JSON数据接口(xml用的较少)。
    • vue:尤雨溪,vue本身借鉴了Angular。个人开发,后端一般用这个。国内使用最多。
    • React:Facebook的产品。
    • Angular:Google的产品。

 

  1. Spring的发展

Spring1.x 时代

在Spring1.x时代,都是通过xml文件配置bean,随着项目的不断扩大,需要将xml配置分放到不同的配置文件中,需要频繁的在java类和xml配置文件中切换。

 Spring2.x时代

随着JDK 1.5带来的注解支持,Spring2.x可以使用注解对Bean进行申明和注入,大大的减少了xml配置文件,同时也大大简化了项目的开发。

那么,问题来了,究竟是应该使用xml还是注解呢?

最佳实践:

  1. 应用的基本配置用xml,比如:数据源、资源文件等;
  2. 业务开发用注解,比如:Service中注入bean等;

Spring3.x到Spring4.x

从Spring3.x开始提供了Java配置方式,使用Java配置方式可以更好的理解你配置的Bean,现在我们就处于这个时代,并且Spring4.x和Spring boot都推荐使用java配置的方式。

  1. Spring的Java配置方式

Java配置是Spring4.x推荐的配置方式,可以完全替代xml配置。

  1. @Configuration 和 @Bean

Spring的Java配置方式是通过 @Configuration 和 @Bean 这两个注解实现的:

1、@Configuration 作用于类上,相当于一个xml配置文件; 类似与springboot的@SpringBootConfiguration

2、@Bean 作用于方法上,相当于xml配置中的

 实例:

@Configuration //通过该注解来表明该类是一个Spring的配置,相当于一个xml文件
@ComponentScan(basePackages = "cn.itcast.springboot.javaconfig") //配置扫描包
public class SpringConfig {
    
    @Bean // 通过该注解来表明是一个Bean对象,相当于xml中的
    public UserDAO getUserDAO(){
        return new UserDAO(); // 直接new对象做演示
    }
    
}
public class Main {
    
    public static void main(String[] args) {
        // 通过Java配置来实例化Spring容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        
        // 在Spring容器中获取Bean对象
        UserService userService = context.getBean(UserService.class);
        
        // 调用对象中的方法
        List list = userService.queryUserList();
        for (User user : list) {
            System.out.println(user.getUsername() + ", " + user.getPassword() + ", " + user.getPassword());
        }
        
        // 销毁该容器
        context.destroy();
    }
}

 读取外部资源:

@Configuration //通过该注解来表明该类是一个Spring的配置,相当于一个xml文件
@ComponentScan(basePackages = "cn.itcast.springboot.javaconfig") //配置扫描包
@PropertySource(value= {"classpath:jdbc.properties"})//多个时逗号双引号隔开
public class SpringConfig {
    
    @Value("${jdbc.url}")
    private String jdbcUrl;
    
    @Bean // 通过该注解来表明是一个Bean对象,相当于xml中的
    public UserDAO getUserDAO(){
        return new UserDAO(); // 直接new对象做演示
    }
    
}

一,springBoot的简介:

简化Spring应用的创建、运行、调试、部署等。使用Spring Boot可以做到专注于Spring应用的开发,而无需过多关注XML的配置。Spring Boot使用“习惯优于配置”的理念,简单来说,它提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题。使用Spring Boot可以不用或者只需要很少的Spring配置就可以让企业项目快速运行起来。

springboot的优点:
使用Java或Groovy开发基于Spring的应用程序非常容易。

它减少了大量的开发时间并提高了生产力。

它避免了编写大量的样板代码,注释和XML配置。

Spring Boot应用程序与其Spring生态系统(如Spring JDBC,Spring ORM,Spring Data,Spring Security等)集成非常容易。

它遵循“自用默认配置”方法,以减少开发工作量。

它提供嵌入式HTTP服务器,如Tomcat,Jetty等,以开发和测试Web应用程序非常容易。

它提供CLI(命令行界面)工具从命令提示符,非常容易和快速地开发和测试Spring Boot(Java或Groovy)应用程序。

它提供了许多插件来开发和测试Spring启动应用程序非常容易使用构建工具,如Maven和Gradle。

它提供了许多插件,以便与嵌入式和内存数据库工作非常容易。

Spring Boot的核心功能

(1)独立运行的Spring项目

Spring Boot可以以jar包的形式进行独立的运行,使用:java -jar xx.jar 就可以成功的运行项目,或者在应用项目的主程序中运行main函数即可;

(2)内嵌的Servlet容器

内嵌容器,使得我们可以执行运行项目的主程序main函数,是想项目的快速运行;

(3)提供starter简化Manen配置

Spring Boot提供了一系列的starter pom用来简化我们的Maven依赖,下边是创建一个web项目中自动包含的依赖,使用的starter pom以来为:spring-boot-starter-web
spring-bootstatus-parent简介:
 1,包含了常用的版本属性,
 修改java的编译版本,
 
 1.8
 

 包含常用的依赖
 1,springboot -starter-xxx:Springboot自带的starter包
 2,xxx-spring-boot-starter;第三方和springBoot集成的starter
 3,druid-spring-boot-starter (druid数据源的原始依赖)自动装配的依赖

spring-boot-starter-web:支持全栈web开发,里面包括了Tomcat和Spring-webmvc。

spring-boot-starter-mail:提供对javax.mail的支持.

spring-boot-starter-ws: 提供对Spring Web Services的支持

spring-boot-starter-test:提供对常用测试框架的支持,包括JUnit,Hamcrest以及Mockito等。

spring-boot-starter-actuator:支持产品环境下的一些功能,比如指标度量及监控等。

spring-boot-starter-jetty:支持jetty容器。

spring-boot-starter-log4j:引入默认的log框架(logback) 

Spring Boot官网还提供了很多的starter pom,请参考:

http://docs.spring.io/spring-boot/docs/1.4.1.RELEASE/reference/htmlsingle/#using-boot-starter


二,创建springboot的三种方式

  • 通过官网下下载骨架包,导入
  • 通过ide插件直接构建(一般选择这种)
  • 通过maven

springboot的parent的设置:

  1. 定义了 Java 编译版本为 1.8 。
  2. 使用 UTF-8 格式编码。
  3. 继承自 spring-boot-dependencies,这个里边定义了依赖的版本,也正是因为继承了这个依赖,所以我们在写依赖时才不需要写版本号。
  4. 执行打包操作的配置。
  5. 自动化的资源过滤。
  6. 自动化的插件配置。
  7. 针对 application.properties 和 application.yml 的资源过滤,包括通过 profile 定义的不同环境的配置文件,例如 application-dev.properties 和 application-dev.yml。

不用 parent:使用公司的parent。自己定义节点。
 

 
         
                 
            org.springframework.boot       
            spring-boot-dependencies       
            2.1.4.RELEASE        
            pom         
            import    
        
    

三,创建Helloword

  1. 编写pom配置文件,加入springboot依赖,parent项目的pom文件的可以实现子依赖对父依赖为可选特性,可以看作springboot是一个有默认父工程的子工程.继承自spring-boot-starter-parent,引入基本的依赖管理配置. 引入spring-boot-starth-web,自动引入springweb的相关包.
  2. 编写控制器类,
  3. 编写配置类,需要加@SpringBootApplication注解,@SpringBootApplication,应用启动类:
    * 主要由三个标签构成,
    * @SpringBootConfiguration:本质上就是一个@configuration,代表是spring容器的主配置类,也就是一个@Component
    * @EnableAutoConfiguration:开启自动化配置,springboot使用这个标签自动的把内置的符合条件的@Configuration类加载到应用.
    * @ComponentScan:自动扫描
  4. @SpringbootApplication只会扫描当前包的下及子包下,不会扫描同级包。所以一般配置类放到根包下。
  5. 当配置类在不在根包下,需要显示指定扫描的包。@ComponentScan(basePackageClasses = )
  6. 运行main方法
package com.example.demo.helloDemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;


/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/1 11:26
 */

@Controller
@RequestMapping("test")
public class HelloController {

    @Autowired
    private ApplicationArguments applicationArguments;


    @RequestMapping("hello")
    @ResponseBody
    public String helloPage(){
        System.out.println(applicationArguments.getNonOptionArgs());
        return "hello springboot";
    }
}
package com.example.demo.helloDemo;

import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;

import java.util.Arrays;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        System.out.println(Arrays.toString(args));
        // 启动配置类方法1
        SpringApplication.run(DemoApplication.class, args);
        // 启动一个配置类方法2.设置banner
        SpringApplication application = new SpringApplication(DemoApplication.class);
        application.setBannerMode(Banner.Mode.OFF);
        application.run(args);
        // 启动一个配置类3
        new SpringApplicationBuilder(DemoApplication.class)
                .bannerMode(Banner.Mode.OFF)
               .run(args);

    }

}

独立运行方式:

  1. * ,直接在ide里运行.执行main方法,
  2. * ,使用基于maven的springboot插件运行
  3. * ,使用maven打包成jar包然后cmd运行.java -jar xx.jar

tomcat配置:

  1. # 修改端口号
    server.port=8080
    # 修改上下文路径
    server.servlet.context-path=/liruilong
    # 配置编码
    server.tomcat.uri-encoding=utf-8
    

四,spring/boot中参数属性设置(注入),

由于application.properties和application.yml文件接受Spring样式占位符 ${...} ,因此 Maven 过滤更改为使用 @..@ 占位符,当然开发者可以通过设置名为 resource.delimiter 的Maven 属性来覆盖 @..@ 占位符。

源码分析

 * 在应用程序启动过程中,可以通过启动参数给应用传递一些额外的参数来控制应用的运行.
 * 1,在main方法中可以直接使用传入的参数.
 * 2,可以任何类中直接通过@Autowired注入一个ApplicationArgument对象.

 * sptingboot参数的主要来源及优先级:

  1.  命令行参数
  2. Servletconfig和ServletContext;
  3. 操作系统环境变量
  4. application-{profile}.propeties或者YAML文件
    1. post 生产(application-dev.yml):dev 开发(application-port.yml): text 测试
    2. spring:
        profiles:
          active: dev
      

       

  5. application.propertiser或者YAML文件,用与设置服务器参数.
  6. 默认读取类目录下的:application.propertiser.
    1. 对于资源文件的加载顺序,
      springBoot提供了方便的propertise绑定机制,:
          默认重application.propertise中加载配置
          资源文件(application.propertise)的加载顺序:
              当前目录/confgi子目录
              当前目录
              calsspath下的/config子目录
              calsspath
          可以通过命令行的方式配置spring.config.name
          spring.config.name配置配置文件的名称
          spring.confgu.location配置配置文件具体加载地址.
package com.example.demo.parentDi;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/5 18:38
 */
@Controller
public class bookController {
    @Autowired
    private Book book;
    @ResponseBody
    @RequestMapping("book")
    public String shuwBook(){
        return book.toString();
    }
}
package com.example.demo.parentDi;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/5 18:20
 */
@PropertySource("classpath:books.properties")
@Setter@Getter@ToString
@Component
public class Book {
    @Value("${name}")
    private String name;
    @Value("${pri}")
    private  double pri;
    @Value("${sum}")
    private  int sum;


}

五,springboot中Banner的设置(springboot中浏览器图标设置),

  1. 直接将banner.txt放到resource目录下.
    package com.example.demo.datasourceDemocontroller;
    
    import org.springframework.boot.Banner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.context.annotation.ComponentScan;
    
    @SpringBootApplication
    
    public class DemoApplication {
    
        public static void main(String[] args) {
          //  SpringApplication.run(DemoApplication.class, args);
            // 取消banner
            SpringApplicationBuilder builder = new SpringApplicationBuilder(DemoApplication.class);
            SpringApplication build = builder.build();
            build.setBannerMode(Banner.Mode.OFF);
            build.run(args);
            
        }
    
    
    }
    

    将图片加工后放到resource下面就可以啦.

六,springboot的参数绑定:

  1. @ConfigurationProperties参数绑定:使用@ConfigurationProperties注解参数绑定标签,可以非常方便的把资源文件的内容绑定到对象上
    1. 如果类是自己写的
      在application.propertise中写入代db前缀的信息.@ConfigurationProperties("db")
    2. ,如果类第三方组件
      加@Bean注解加@ConfigurationProperties("db")用在返回Bean 的方法上
  2. 支持松绑定
  3. 对于命令行可以使用--来输入参数.
server.port=8080

#数据源配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=mysql
package com.example.demo.configureationPropertise;

import com.example.demo.configureationPropertise.MyDruidSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/2 12:44
 */
@Controller
public class DateSource {

    @Autowired
    private MyDruidSource myDruidSource;
    @RequestMapping("dataSource")
    @ResponseBody
    public String dataSource(){
     //   System.out.println(myDruidSource.toString());
        System.out.println(myDruidSource.toString());
        return "dataSourct";
    }
}
package com.example.demo.configureationPropertise;


import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/2 12:31
 */
@Setter
@Getter
@ToString
@Component
@ConfigurationProperties("db")
public class MyDruidSource {
    private String username;
    private String password;
    private String url;
    private String driverClassName;


}
package com.example.demo.configureationPropertise;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/2 12:47
 */
@SpringBootApplication
public class Appconfig {
    @Bean
    @ConfigurationProperties("db")
    public MyDruidSource dataSource(){
            return new MyDruidSource();
    }
    public static void main(String[] args) {

        SpringApplication.run(Appconfig.class, args);
    }
}


 Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率。
 例如开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器、equals等方法,而且需要维护,当属性多时会出现大量的getter/setter方法,这些显得很冗长也没有太多技术含量,一旦修改属性,就容易出现忘记修改对应方法的失误。
 Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。出现的神奇就是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。
 


 org.projectlombok
 lombok
 1.16.20
 provided
 
  1.  @Data注解在类上,会为类的所有属性自动生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。
  2.  @Getter/@Setter使用@Getter/@Setter注解,此注解在属性上,可以为相应的属性自动生成Getter/Setter方法,示例如下:
  3.  @NonNull该注解用在属性或构造器上,Lombok会生成一个非空的声明,可用于校验参数,能帮助避免空指针。
  4. @Cleanup自动调用close()方法,很大的简化了代码。
  5. @EqualsAndHashCode会使用所有非静态(non-static)和非瞬态(non-transient)属性来生成equals和hasCode,也能通过exclude注解来排除一些属性。
  6. @ToString类使用@ToString注解,Lombok会生成一个toString()方法,默认情况下,会输出类名、所有属性(会按照属性定义顺序),用逗号来分割。
  7. @NoArgsConstructor,@RequiredArgsConstructor and @AllArgsConstructor无参构造器、部分参数构造器、全参构造器。Lombok没法实现多种参数构造器的重载。

yaml配置和properties区别:

  1. 不同于properties文件的无序,yaml配置是有序的,这一点在有些配置中是非常有用的,例如在Spring Cloud Zuul的配置中,当我们配置代理规则时,顺序就显得尤为重要了。当然yaml配置也不是万能的,例如,yaml配置目前不支持@PropertySource注解。
  2. # YAML 配置  (*.yml || *.yaml)
  3. yaml也支持数组和对象注入
    server:
      port: 8081
    redis:
      port: 6397
      hosts:
        - 192.168.66.128
        - 192.168.66.128
        - 192.168.66.128
        - 192.168.66.128
      redisList:
        - port: 6397
          hosts: 192.168.22.128
        - port: 6833
          hosts: 192.168.22.128
    
    
    
    package com.example.demo.yamlDemo;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @Description :
     * @Author: Liruilong
     * @Date: 2019/10/5 19:18
     */
    @Getter@Setter@ToString
    @Component
    @ConfigurationProperties(prefix = "redis")
    public class Redis {
        private String port;
        private List hosts;
        private List redisList;
    
    }
    
    package com.example.demo.yamlDemo;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    
    
    /**
     * @Description :
     * @Author: Liruilong
     * @Date: 2019/10/5 19:25
     */
    @Controller
    public class ymlDemoController {
    
        @Autowired
        private Redis r;
        
        @ResponseBody
        @RequestMapping("yml")
        public String showReids(){
            System.out.println(r.toString());
            return r.toString();
        }
    }
    

    默认的加载顺序

  4. 
    			
    				${basedir}/src/main/resources
    				true
    				
    					**/application*.yml
    					**/application*.yaml
    					**/application*.properties
    				
    			
    			
    

     

七,spring整合持久层技术,(集成mybatis,jdbcTmplate,Jpa)

server.port=8080

#数据源配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=mysql

# 打印sql语句
logging.level.com.example.demo.mybatisDemo.Mapper=debug
# 加载mybatis配置文件 可以不写
# mybatis.config-location=classpath:mybatis-config.xml
# 指定别名 可以不写
# mybatis.type-aliases-package=com.example.demo.mybatisDemo.POJO.user
# 指定映射文件的位置  可以不写
# mybatis.mapper-locations=classpath:com/example/demo/mybatisDemo/Mapper/*Mapper.xml

package com.example.demo.mybatisDemo.controller;

import com.example.demo.mybatisDemo.POJO.user;
import com.example.demo.mybatisDemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/3 9:47
 */
@Controller
public class UserController {

    @Autowired
    private UserService userServiceimpl;
    @ResponseBody
    @RequestMapping("select")
   public List select(){
        return userServiceimpl.select();
    }
    @RequestMapping("reig")
    void insert(user user){
        userServiceimpl.insert(user);
    }
}
package com.example.demo.mybatisDemo.Mapper;

import com.example.demo.mybatisDemo.POJO.user;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;
/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/2 20:49
 */
@Repository
public interface UserMapper {
    List select();
    void insert(user user);
}



   

    
    
        insert into user values (1,"李四","10000")
    
package com.example.demo.mybatisDemo.POJO;

import lombok.Getter;
import lombok.Setter;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/2 20:42
 */
@Setter@Getter
public class user {

    private  Long id;
    private  String name;
    private  String resource;

}
package com.example.demo.mybatisDemo.service;

import com.example.demo.mybatisDemo.POJO.user;

import java.util.List;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/3 9:43
 */
public interface UserService {
    List select();
    void insert(user user);
}
package com.example.demo.mybatisDemo.service;

import com.example.demo.mybatisDemo.Mapper.UserMapper;
import com.example.demo.mybatisDemo.POJO.user;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/3 9:43
 */
@Service
public class UserServiceimpl implements UserService{
    @Autowired
    private UserMapper userMapper;
    @Override
    public List select() {
        return userMapper.select();
    }

    @Override
    public void insert(user user) {
        userMapper.insert(user);
    }
}
package com.example.demo.mybatisDemo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/3 9:38
 */
@SpringBootApplication
@MapperScan("com.example.demo.mybatisDemo.Mapper") // 数据源配置
// 扫描mapper
public class Appconfig {
    public static void main(String[] args) {
        SpringApplication.run(Appconfig.class, args);

    }
}

springboot-mybatis多数据源配置:

 

package com.example.demo.mybatisDemo.config;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import javax.sql.DataSource;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/11/25 8:44
 */
@Configuration
@MapperScan(basePackages = "com.example.demo.mybatisDemo.Mapper1", sqlSessionFactoryRef ="sqlSessionFactory1", sqlSessionTemplateRef = "sqlSessionTemplate1")
public class DataSourceConfig {
    @Resource(name = "dsOne")
    DataSource dsOne;


    @Bean
    SqlSessionFactory sqlSessionFactory1() {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        try{
            bean.setDataSource(dsOne);
            return bean.getObject();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Bean
    SqlSessionTemplate sqlSessionTemplate1(){
        return new SqlSessionTemplate(sqlSessionFactory1());
    }

}

 springboot整合jdbctemplate

package com.example.demo.jdbctemplate;

import org.apache.catalina.LifecycleState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/11/24 19:45
 */
@Service
public class UserService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public Integer addUser(User user){

        return jdbcTemplate.update("INSERT INTO users(username,password) VALUES (?, ? )",user.getUsername(), user.getPassword());
    }

    public List getAllUser(){
        // 属性名不同的
        return jdbcTemplate.query("SELECT  * FROM  users ", new RowMapper() {

            @Override
            public User mapRow(ResultSet rs, int rowNum) throws SQLException {

                return null;
            }
        });
        //属性名相同
        return jdbcTemplate.query("", new BeanPropertyRowMapper<>(User.class));
    }


}

springboot----jdbctemplate多数据源的配置

spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.one.url=jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=UTF-8
spring.datasource.one.username=root
spring.datasource.one.password=mysql

spring.datasourceoe.tow.type=com.alibaba.druid.pool.DruidDataSource
spring.datasourceoe.tow.url=jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=UTF-8
spring.datasourceoe.tow.username=root
spring.datasourceoe.tow.password=mysql        

 

package com.example.demo.jdbctemplate;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/11/25 7:51
 */
@Configuration
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.one")
    DataSource dsOne(){
        return DruidDataSourceBuilder.create().build();
    }
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.tow")
    DataSource dsTow(){
        return DruidDataSourceBuilder.create().build();
    }

}

 

package com.example.demo.jdbctemplate;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/11/25 7:56
 */
@Configuration
public class jdbcTemplateConfig {

    @Bean // @Qualifier 指定前缀
    JdbcTemplate jdbcTemplateOne(@Qualifier("dsOne")DataSource dsOne){
        return new JdbcTemplate(dsOne);
    }
    @Bean // @Qualifier 指定前缀
    JdbcTemplate jdbcTemplateTow(@Qualifier("dsTow")DataSource dsOne){
        return new JdbcTemplate(dsOne);
    }

}
package com.example.demo.jdbctemplate;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/11/24 19:51
 */
@Component
public class test {

    @Autowired
    @Qualifier("jdbcTemplateOne")
    JdbcTemplate jdbcTemplateOne;

    @Resource(name = "jdbcTemplateTow")
    JdbcTemplate jdbcTemplateTow;

    public static void main(String[] args) {

    }
    public Integer addUserOne(User user){

        return jdbcTemplateOne.update("INSERT INTO users(username,password) VALUES (?, ? )",user.getUsername(), user.getPassword());
    }
    public Integer addUserTow(User user){

        return jdbcTemplateTow.update("INSERT INTO users(username,password) VALUES (?, ? )",user.getUsername(), user.getPassword());
    }
    

}

 

八,spring的自动装配原理

  • 1,springApplication.run(AppConfig.class ,agrs):执行流程中调用refershcontext(context)
     
  • 2,refershcontext(context)内部会解析我们配置类上的标签,实现自动装配功能的注解@EnableTransactionManagement
  • 3,然后会解析@EnableAutoConfiguration这个注解里的@import引入的配置类AutoConfigurationImportSelector.class
  • 4,AutoConfigurationImportSelector类中有一个方法中
  • List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
  • 5,SpringFactoriesLoader.loadFactoryNames的作用就是读取jar包中的/项目的META-INF/spring-factories文件.
  • 6,spring.factoryies中配置了自动装配的类,根根据条件配置.

 

九,springboot的事务管理

  • 基于注解的事务管理步骤:
    • 在主配置类中粘上@EnableTransactionManagement,表示开启事务注解驱动的支持, 等价于xml的
    • 在需要是的事务上加上@Transactional 表示下面的方法都需要事务
  • 基于xml的注解装配
  • 基于注解的事务管理步骤:
  • package com.example.demo.mybatisDemo;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ImportResource;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.sql.DataSource;
    
    /**
     * @Description :
     * @Author: Liruilong
     * @Date: 2019/10/3 9:38
     */
    @EnableTransactionManagement //等价于xml的
    @SpringBootApplication
    @MapperScan("com.example.demo.mybatisDemo.Mapper")// 扫描mapper
    // 读取配置文件
    //@ImportResource("classpath:applicationContext.xml")
    
    public class Appconfig {
    
        @Bean
        public PlatformTransactionManager txManager(DataSource dataSource){
            DataSourceTransactionManager txManager = new DataSourceTransactionManager();
            txManager.setDataSource(dataSource);
            return txManager;
        }
    
        public static void main(String[] args) {
            SpringApplication.run(Appconfig.class, args);
        }
    }
    
    
    
  •  

 

十,springboot的静态资源处理(自定义欢迎页处理):

  • private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
    			"classpath:/resources/", "classpath:/static/", "classpath:/public/" };

    先静态,静态没有到动态下寻找.直接在页面下写Index文件即可.

  • 静态资源:
  • 默认情况下,springboot会从calsspath下的/static,/public,/resources,/META-INF/resource下加载静态资源
  • 可以通过修改spring.resources.static-locations 来修改静态资源加载地址.或则通过Java类来实现.
    spring.resources.static-locations=classpath:/static,/public,/resources,/META-INF/resource,/mydir
  • 因为应用是打包为jar包,所以之前的webapp不会执行.
  • springboot的热部署:
  • 
            
                org.springframework.boot
                spring-boot-devtools
                2.0.2
                true
                

 

十一,SpringBoot集成Freemarker和Thymeleaf

  • 
            
                org.springframework.boot
                spring-boot-starter-thymeleaf
            
            
                org.springframework.boot
                spring-boot-starter-freemarker
            

     

  • 对于模板引擎,默认的加载路径为:calsspath下的/templates.

  • Thymeleaf是一种用于Web和独立环境的现代服务器端的Java模板引擎。

    Thymeleaf的主要目标是将优雅的自然模板带到开发工作流程中,并将HTML在浏览器中正确显示,并且可以作为静态原型,让开发团队能更容易地协作。Thymeleaf能够处理HTML,XML,JavaScript,CSS甚至纯文本。




    
    Title


id 姓名 地址 性别

常用th属性使用

使用Thymeleaf属性需要注意点以下五点:

  • 一、若要使用Thymeleaf语法,首先要声明名称空间: xmlns:th="http://www.thymeleaf.org"
  • 二、设置文本内容 th:text,设置input的值 th:value,循环输出 th:each,条件判断 th:if,插入代码块 th:insert,定义代码块 th:fragment,声明变量 th:object
  • 三、th:each 的用法需要格外注意,打个比方:如果你要循环一个div中的p标签,则th:each属性必须放在p标签上。若你将th:each属性放在div上,则循环的是将整个div。
  • 四、变量表达式中提供了很多的内置方法,该内置方法是用#开头,请不要与#{}消息表达式弄混。
  • 五、th:insert,th:replace,th:include 三种插入代码块的效果相似,但区别很大。

常用th属性解读

html有的属性,Thymeleaf基本都有,而常用的属性大概有七八个。其中th属性执行的优先级从1~8,数字越低优先级越高。

  • 一、th:text :设置当前元素的文本内容,相同功能的还有th:utext,两者的区别在于前者不会转义html标签,后者会。优先级不高:order=7
  • 二、th:value:设置当前元素的value值,类似修改指定属性的还有th:srcth:href。优先级不高:order=6
  • 三、th:each:遍历循环元素,和th:text或th:value一起使用。注意该属性修饰的标签位置,详细往后看。优先级很高:order=2
  • 四、th:if:条件判断,类似的还有th:unlessth:switchth:case。优先级较高:order=3
  • 五、th:insert:代码块引入,类似的还有th:replaceth:include,三者的区别较大,若使用不恰当会破坏html结构,常用于公共代码块提取的场景。优先级最高:order=1
  • 六、th:fragment:定义代码块,方便被th:insert引用。优先级最低:order=8
  • 七、th:object:声明变量,一般和*{}一起配合使用,达到偷懒的效果。优先级一般:order=4
  • 八、th:attr:修改任意属性,实际开发中用的较少,因为有丰富的其他th属性帮忙,类似的还有th:attrappend,th:attrprepend。优先级一般:order=5
  •  

 

FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

  • 导入依赖
             
                org.springframework.boot
                spring-boot-starter-freemarker
            

     

  • 创建ftl文件
    
    
        
        freemarker
    
    
    hello ${name}
    
    

     

  • 编写控制器
    package com.example.demo.freemarker;
    
    import org.jcp.xml.dsig.internal.MacOutputStream;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    /**
     * @Description :
     * @Author: Liruilong
     * @Date: 2019/10/3 21:12
     */
    @Controller
    public class FreemarkerController {
    
        @RequestMapping("name")
        public String helloPage(Model model){
            model.addAttribute("name","springboot");
            return "hello";
        }
    }
    

     

  • #freemarker 获取session域
    spring.freemarker.expose-session-attributes=true

freemarker学习博客:https://www.cnblogs.com/itdragon/p/7750903.html




    
    freemarker



    <#list users as u>
        <#if u.id=4>
            <#break >
        
        
编号 用户名 用户地址 性别
${u.id} ${u.name} ${u.addres} <#if u.fix==0> 男 <#elseif u.fix=1> 女 <#elseif u.fix=2> 未知
字符串输出: ${"Hello ${name} !"} / ${"Hello " + name + " !"}

<#assign cname=r"特殊字符完成输出(http:\www.baidu.com)">

${cname}

字符串截取 :

通过下标直接获取下标对应的字母: ${name[2]}

起点下标..结尾下标截取字符串:${name[0..2]}

算数运算: <#-- 支持"+"、"-"、"*"、"/"、"%"运算符 --> <#assign number1 = 10> <#assign number2 = 5> "+" : ${number1 + number2} "-" : ${number1 - number2} "*" : ${number1 * number2} "/" : ${number1 / number2} "%" : ${number1 % number2}

比较运算符: <#if number1 + number2 gte 12 || number1 - number2 lt 6> "*" : ${number1 * number2} <#else> "/" : ${number1 / number2}

内建函数: <#assign data = "abcd1234">:${data}

第一个字母大写:${data?cap_first}

所有字母小写:${data?lower_case}

所有字母大写:${data?upper_case}

<#assign floatData = 12.34>:${floatData}

数值取整数:${floatData?int}

获取集合的长度:${users?size}

时间格式化:${dateTime?string("yyyy-MM-dd")}

空判断和对象集合: <#if users??> <#list users as user > ${user.id} - ${user.name}

<#else> ${user!"变量为空则给一个默认值"}

Map集合: <#assign mapData={"name":"程序员", "salary":15000}> 直接通过Key获取 Value值:${mapData["name"]}

通过Key遍历Map: <#list mapData?keys as key> Key: ${key} - Value: ${mapData[key]}

通过Value遍历Map: <#list mapData?values as value> Value: ${value}

List集合: <#assign listData=["ITDragon", "blog", "is", "cool"]> <#list listData as value>${value}

include指令: 引入其他文件:<#include "otherFreeMarker.ftl" />

macro宏指令:

<#macro mo> 定义无参数的宏macro--${name}

使用宏macro: <@mo />

<#macro moArgs a b c> 定义带参数的宏macro-- ${a+b+c}

使用带参数的宏macro: <@moArgs a=1 b=2 c=3 />

命名空间:

<#import "otherFreeMarker.ftl" as otherFtl>

${otherFtl.otherName}

<@otherFtl.addMethod a=10 b=20 />

<#assign otherName="修改otherFreeMarker.ftl中的otherName变量值"/>

${otherFtl.otherName}

<#assign otherName="修改otherFreeMarker.ftl中的otherName变量值" in otherFtl />

${otherFtl.otherName}

Title 其他FreeMarker文件 <#macro addMethod a b > result : ${a + b} <#assign otherName="另外一个FreeMarker的变量">
package com.example.demo.freemarker;


import com.example.demo.freemarker.bena.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.*;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/3 21:12
 */
@Controller
public class FreemarkerController {

    @RequestMapping("name")
    public String helloPage(Model model){
        model.addAttribute("name","springboot");
        return "hello";
    }
    @GetMapping("user")
    public String user(Model model){
        List users = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < 15; i++) {
            User user = new User();
            user.setId(i);
            user.setName("java"+ ">>"+i);
            user.setAddres("liruiong"+ ">>" + i);
            user.setFix(random.nextInt(3));
            users.add(user);
        }
        Map dataMap = new HashMap();
        model.addAttribute("name", "itdragon博客");
        model.addAttribute("dateTime", new Date());
        model.addAttribute("dataMap",dataMap);
        model.addAttribute("name", "李瑞龙");
        model.addAttribute("users",users);
        return "userftl";
    }

}

数据类型:

和java不同,FreeMarker不需要定义变量的类型,直接赋值即可。

字符串: value = "xxxx" 。如果有特殊字符 string = r"xxxx" 。单引号和双引号是一样的。

数值:value = 1.2。数值可以直接等于,但是不能用科学计数法。

布尔值:true or  false。

List集合:list = [1,2,3] ; list=[1..100] 表示 1 到 100 的集合,反之亦然。

Map集合:map = {"key" : "value" , "key2" : "value2"},key 必须是字符串哦!

实体类:和EL表达式差不多,直接点出来。

字符串操作

字符串连接:可以直接嵌套${"hello , ${name}"} ; 也可以用加号${"hello , " + name}

字符串截取:string[index]。index 可以是一个值,也可以是形如 0..2 表示下标从0开始,到下标为2结束。一共是三个数。

比较运算符

== (等于),!= (不等于),gt(大于),gte(大于或者等于),lt(小于),lte(小于或者等于)。不建议用 >,<  可能会报错!

一般和 if 配合使用

内建函数

FreeMarker 提供了一些内建函数来转换输出,其结构:变量?内建函数,这样就可以通过内建函数来转换输出变量。

1. html: 对字符串进行HTML编码;
2. cap_first: 使字符串第一个字母大写;
3. lower_case: 将字符串转成小写;
4. upper_case: 将字符串转成大写;
5. size: 获得集合中元素的个数;
6. int: 取得数字的整数部分。

变量空判断

 !    指定缺失变量的默认值;一般配置变量输出使用
??    判断变量是否存在。一般配合if使用 <#if value??>

宏指令

可以理解为java的封装方法,供其他地方使用。宏指令也称为自定义指令,macro指令

语法很简单:<#macro val > 声明macro ; 使用macro <@val />  

命名空间

可以理解为java的import语句,为避免变量重复。一个重要的规则就是:路径不应该包含大写字母,使用下划线_分隔词语,myName --> my_name

语法很简单:<#import "xxx.ftl" as val> 

设置顶层变量.

十二,SpringBoot中@ControllerAdvice的使用(统一异常的处理)

  1. 处理全局异常
  2. 预设全局数据
  3. 请求参数预处理

一,处理全局异常

  • 1,通过@ControllerAdvice:
    • 通过使用@ControllerAdvice定义统一的异常处理页面,而不是在每个Controller中逐个定义
    • @ExceptionHandler用来定义函数,针对异常的类型.
  • 2,统一的异常处理页面,
    •     > springboot默认情况下,把所有的错误定义到/error的这个处理路径上,由BasicErrorController类完成处理
    •     >springboot提供了默认的替换错误页面的路径.
    •     >优先级,精确的高于模糊的,动态的高于静态的
  • 静态错误页面:
    • src/resources/public/error/404.html
  • 模板页面:
    • src/resources/templates/error/404.ftl
  • package com.example.demo.freemarker;
    
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    /**
     * @Description :
     * @Date: 2019/10/3 21:37
     * @Author: Liruilong
     */
    @ControllerAdvice //controller的增强
    public class ErrorController {
    
        // 可以指定异常类型,当触发时指定所在的异常.不指定时默认所有异常处理器
        @ExceptionHandler
        public void handlerError(Exception ex, HandlerMethod handlerMethod, HttpServletResponse response) throws IOException {
            response.setContentType("text/html;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.write("统一的异常处理");
            out.write("异常描述:" + ex.getMessage());
            out.write("发生异常的类:"+handlerMethod.getBean().getClass().getName());
            out.write("发生异常的方法:"+handlerMethod.getMethod().getName());
    
        }
    
        @ExceptionHandler(ArithmeticException.class)
        public void myEscrption(ArithmeticException ex, HttpServletResponse response ) throws IOException {
            response.setContentType("text/html;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.write("算数异常处理");
            System.out.println("异常描述:" + ex.getMessage());
        }
       @ExceptionHandler(ArithmeticException.class)
        public ModelAndView myException(ArithmeticException ex,HttpServletResponse response){
    
           ModelAndView modelAndView = new ModelAndView("erroe");
    
           modelAndView.addObject("error", "异常页面");
    
           return modelAndView;
    
       }
    
    }
    

二,预设全局数据

定义一个controller增强

package com.example.demo.controlleradvice;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/8 23:48
 */
@ControllerAdvice
public class DemoDate {
    @ModelAttribute(value = "info")
    public Map mydata(){
        Map map= new HashMap<>();
        map.put("name","javaboy");
        map.put("address", "www.javaboy.org");
        return map;
    } ;

}

定义一个contrlooerl

package com.example.demo.controlleradvice;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;


/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/8 23:52
 */
@RestController
public class Controller {
    @GetMapping("/hellos")
    public String hello(Model model){
        // 转换为Map
        Map map = model.asMap();
        map.forEach((o1, o2) ->{
            System.out.println(o1 + o2);
        });
        return "hello";
    }
}

请求参数预处理:
当前端传来的相同键的不同值得时候,会将相同的键的值合并到一起.可以指定前缀,然后通过前缀来区分不同的值.

 @GetMapping("/book")
    public void addBook(@ModelAttribute("a")Book book, @ModelAttribute("b") User user){
        System.out.println(book.toString());
        System.out.println(user.toString());
    }




package com.example.demo.controlleradvice;

import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/8 23:48
 */


    @InitBinder("a")
    public void initA(WebDataBinder binder){
        binder.setFieldDefaultPrefix("a");
    }
    @InitBinder("b")
    public void initB(WebDataBinder binder){
        binder.setFieldDefaultPrefix("b");
    }
}

spring自定义异常数据,当不对异常信息进行处理的时候,spring会对异常信息进行处理,并替换为指定的错误页面

可以使用默认的异常处理的参数,

可一个使用自定义的参数处理.
 

  @ResponseBody
    @GetMapping("errorDemo")
    public String errorDemo(){
        int i  = 1/0;
        return "异常测试";
    }
// 500.html




    
    Title


path timestamp message
att

spring自定义异常处理页面.
 

package com.example.demo.freemarker;

import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.DefaultErrorViewResolver;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/9 10:55
 */
@Component
public class MyErrorviewResolver extends DefaultErrorViewResolver {
    /**
     * Create a new {@link DefaultErrorViewResolver} instance.
     *
     * @param applicationContext the source application context
     * @param resourceProperties resource properties
     */
    public MyErrorviewResolver(ApplicationContext applicationContext, ResourceProperties resourceProperties) {
        super(applicationContext, resourceProperties);
    }

    @Override
    public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map model) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        modelAndView.addAllObjects(model);
        return modelAndView;
    }
}

十二,Springboot组册Servlet组件

  • 1,定义tomcat容器,
    •     >servlet.post:定制监听端口.
    •     >server.session.timeout:session的有效时间
  • 2,添加Servlet组件,
  •     >在配置类上添加@ServletComponetScan,会自动扫描添加了@webServlst,@WebFilter,和@WebListener类.
    package com.example.demo.servlet;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.ServletComponentScan;
    
    /**
     * @Description :
     * @Author: Liruilong
     * @Date: 2019/10/4 10:33
     */
    @SpringBootApplication
    @ServletComponentScan //扫描Servlet
    public class Appconfigs {
        public static void main(String[] args) {
    
            SpringApplication.run(Appconfigs.class, args);
        }
    }
    
    package com.example.demo.servlet;
    
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * @Description :  servlet
     * @Author: Liruilong
     * @Date: 2019/10/4 10:30
     */
    @WebServlet(urlPatterns = "/testServlet")
    public class TestServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("testServlet");
            super.service(req, resp);
        }
    }
    package com.example.demo.servlet;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import java.io.IOException;
    
    /**
     * @Description : 拦截请求
     * @Author: Liruilong
     * @Date: 2019/10/4 10:37
     */
    @WebFilter(urlPatterns = "/*")
    public class TestFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("test Filter");
            filterChain.doFilter(servletRequest,servletResponse);
        }
        @Override
        public void destroy() {
    
        }
    }
    
    package com.example.demo.servlet;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    
    /**
     * @Description :  监听启动
     * @Author: Liruilong
     * @Date: 2019/10/4 10:59
     */
    @WebListener
    public class TestListener  implements ServletContextListener {
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            System.out.println("启动了^^^^^^");
        }
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            System.out.println("关闭了^^^^^^^^");
        }
    }

     

  •     >通过创建bean来创建,不需要使用注解
    package com.example.demo.servlet;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.boot.web.servlet.ServletComponentScan;
    import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
    import org.springframework.boot.web.servlet.ServletRegistrationBean;
    import org.springframework.context.annotation.Bean;
    
    /**
     * @Description :
     * @Author: Liruilong
     * @Date: 2019/10/4 10:33
     */
    @SpringBootApplication
    @ServletComponentScan //扫描Servlet
    public class Appconfigs {
        @Bean
        public ServletRegistrationBean testServlet(){
            ServletRegistrationBean bean = new ServletRegistrationBean();
            bean.setServlet(new TestServlet());
            bean.addUrlMappings("/testServlet");
            return bean;
        }
        @Bean
        public FilterRegistrationBean testFilter(){
            FilterRegistrationBean bean = new FilterRegistrationBean();
            bean.setFilter(new TestFilter());
            bean.addUrlPatterns("/*");
            return bean;
        }
        @Bean
        public ServletListenerRegistrationBean testListener(){
            ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean<>();
            bean.setListener(new TestListener());
            return bean;
        }
        public static void main(String[] args) {
    
            SpringApplication.run(Appconfigs.class, args);
        }
    }
    
    • ServletListenerRegistrationBean;
    • ServletRegistrationBean;
    • FilterRegistrationBean;

十二,Springboot文件上传:

  • 任然使用MuitiparFile完成上传,springboor使用sevlert3的part完成文件上传,不是使用fileupload;
  • ,上传相关配置,
  • ,也可以通过创建一个MultipartConfigElement类型的bean对上传进行配置
  • 对于上传文件的处理:因为打包为jar包,所以一般会把上传的文件放到其他位置,并通过设置.
  • spring.resources.static-locations=来完成对资源的定位
    #文件大小
    spring.servlet.multipart.max-file-size=4KB
    # 文件写入路径
    spring.servlet.multipart.location=
  • package com.example.demo.fileup;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.util.FileCopyUtils;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.multipart.MultipartFile;
    
    
    import javax.servlet.http.HttpServletRequest;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.*;
    
    /**
     * @Description :
     * @Author: Liruilong
     * @Date: 2019/10/4 12:12
     */
    @Controller
    public class fileupController {
    
        @Value("${file.path}")
        private String filePath;
    
        @ResponseBody
        @RequestMapping("/upfile")
        public String upfile(MultipartFile multipartFile) throws IOException {
            if (multipartFile.isEmpty()){
                System.out.println("没有传入数据");
            }
            String filenamefix = multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf("."));
            String newFile = UUID.randomUUID().toString() + filenamefix;
            FileCopyUtils.copy(multipartFile.getInputStream(),new FileOutputStream(new File(filePath+newFile)));
            return "文件已经上传啦!!!";
        }
        // 分文件夹存取
        SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
        @ResponseBody
        @PostMapping("/upload")
        public String upload(MultipartFile multipartFile, HttpServletRequest request) throws IOException {
            // 将文件存入指定的文件夹
            String format = sdf.format(new Date());
            String realPath = request.getServletContext().getRealPath("/img") + format;
            // 创建文件存放路径
            File folder = new File(realPath);
            folder.mkdir();
            if (!folder.exists()){
                folder.mkdirs();
            }
            String oldName = multipartFile.getOriginalFilename();
            String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
            // 将文件移动到指定的文件夹.
            File file = new File(folder,newName);
            System.out.println(file.getName());
            multipartFile.transferTo(new File(folder, newName));
            return newName;
        }
    
        // 多文件上传
        @ResponseBody
        @PostMapping("/uploads")
        public String uploads(MultipartFile[] multipartFiles,HttpServletRequest request){
            // 创建文件路径
            String fommad = sdf.format(new Date());
            String filepath = request.getServletContext().getRealPath("/img") + fommad;
            File file = new File(filepath);
            if (!file.exists()){
                file.mkdirs();
            }
            Arrays.stream(multipartFiles).forEach(
                    (MultipartFile multipart) ->{
                        String filename = multipart.getOriginalFilename();
                        String newName = UUID.randomUUID().toString() + filename.substring(filename.lastIndexOf("."));
                        try {
                            multipart.transferTo(new File(file, newName));
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
            );
            return "上传成功";
        }
    }
    //UUID.randomUUID().toString()是javaJDK提供的一个自动生成主键的方法。UUID(Universally Unique Identifier)全局唯一标识符,
    // 是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的,是由一个十六位的数字组成,表现出来的形式。
    // 由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同),
    // 时钟序列,全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得),UUID的唯一缺陷在于生成的结果串会比较长。
    
  • 文件上传页面

    
    
    
        
        文件上传
    
    
    
    

    基于AJAX的文件上传

    多文件上传

    单文件上传

    十三,springboot中注册拦截器

  • 旧方法
  • package com.example.demo.Binterceptor;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    /**
     * @Description :
     * @Author: Liruilong
     * @Date: 2019/10/4 15:24
     */@SpringBootApplication
    public class Appconfgi  extends WebMvcConfigurerAdapter {
    
    
        public static void main(String[] args) {
            SpringApplication.run(Appconfgi.class,args);
        }
    
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 注册一个拦截器
            registry.addInterceptor(myInterceptor()).addPathPatterns("/*");
            super.addInterceptors(registry);
        }
        @Bean
        public MyInterceptor myInterceptor(){
            return new MyInterceptor();
        }
    }
    
  • package com.example.demo.Binterceptor;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * @Description :
     * @Author: Liruilong
     * @Date: 2019/10/4 15:28
     */
    public class MyInterceptor extends HandlerInterceptorAdapter {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("拦截没有哎 $_$");
            //return super.preHandle(request, response, handler);
            return true;
    
        }
    }
    
  • 新方法
  • package com.example.demo.interceptor;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * @Description :
     * @Author: Liruilong
     * @Date: 2019/10/17 16:00
     */
    public class MyInterceptors implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("请求进入拦截");
            //  只有该方法返回ture才会执行之后的.
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("请求中拦截");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("请求后拦截");
        }
    }
    
    package com.example.demo.interceptor;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    /**
     * @Description : 拦截器注册
     * @Author: Liruilong
     * @Date: 2019/10/18 14:53
     */
    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
        @Bean
        MyInterceptors myInterceptors(){
            return new MyInterceptors();
        }
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(myInterceptors()).addPathPatterns("/**");
        }
    }
    
    package com.example.demo.interceptor;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * @Description :
     * @Author: Liruilong
     * @Date: 2019/10/18 15:01
     */
    @SpringBootApplication
    public class config {
    
        public static void main(String[] args) {
            SpringApplication.run(config.class);
        }
    }
    

     

十四,springboot整合Json和Gson和Fastjson

HttpMessageConverter,:将服务返回的对象序列化为JSON字符串.将前端的JSON数据转化为Java对象

所以的JSON都离不开HttpMassageConverter.Spring MVC 自动配置了Jackson和GSON.

当需要对JSON数据进行相应的格式设置时,可以通过注解或者其他的方式设置.
方法一:

package com.example.demo.jsonDemo;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.persistence.SecondaryTable;
import java.util.Date;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/7 21:46
 */
@Getter@Setter@ToString
public class User {
    private int id ;
    private String name;
    private String sex;
    private String addres;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date birdei;


}

方法二:自己注入ObjectMapper
 

package com.example.demo.jsonDemo.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Controller;

import java.text.SimpleDateFormat;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/7 22:13
 */
@Configuration
public class WebMvcConfig {

   @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
        MappingJackson2HttpMessageConverter cborHttpMessageConverter =
                new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy/MM/dd"));
        cborHttpMessageConverter.setObjectMapper(objectMapper);
        return cborHttpMessageConverter;
    }

    @Bean
    public  ObjectMapper objectMapper(){
        return new ObjectMapper().setDateFormat(new SimpleDateFormat("yyyy/MM/dd"));
    }
}

 

十五,Springboot中通过cors解决跨域问题

同源策略:安全策略,是浏览器最核心最基本的安全功能,现在所有支持JavaScript的浏览器都会使用这个策略,它是浏览器最核心的功能,所谓同源就是指协议,域名已及端口号都要相同,同源策略是出于安全方面的考虑.在实际开发开发中,需要实现跨域的请求,

对于跨域的解决方案有基于前端的JSONP,但JSONP有局限性,即只支持GET请求,不支持其他类型的请求,
CORS(跨域资源共享):是一个W3C标准,他是浏览器技术规范,提供了web服务器重不同的网域传来沙盒脚本的方法.避开浏览器的同源策略.spring框架中对CORS提供了相应的解决办法,
建立两个springboot项目实现前后端分离.
 

十六,springboot中使用xml配置:

package com.example.demo.xmlDemo;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

/**
 * @Description : 基于xml装配bean
 * @Author: Liruilong
 * @Date: 2019/10/18 13:42
 */

@Configuration
@ImportResource(locations = "classpath:beans.xml")
public class webMvcConfig {

}

十七,ApplicationRunner实现系统启动任务

系统启动任务只执行一次,可以获取系统参数,多个时按照优先级执行
 

package com.example.demo.applicationrunerApplication;

import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/20 0:44
 */
@Component
@Order(5)
public class MycommandLineRunner2 implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("MyCommandLineRunner2" + Arrays.toString(args));
    }
}
package com.example.demo.applicationrunerApplication;

import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/20 0:42
 */
@Component
@Order(7)// 默认的优先级最低,
public class MycommandLineRunnerl implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("MyCommandLineRunner1" + Arrays.toString(args));
    }
}
package com.example.demo.applicationrunerApplication;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/18 16:59
 */
@Component
@Order(99)
public class MyApplicationRunner01 implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 获取启动的所有参数
        String[] sourceArgs = args.getSourceArgs();
        System.out.println(Arrays.toString(sourceArgs));
        // 获取所有的值
        args.getNonOptionArgs().stream().forEach(System.out::print);
        args.getOptionNames();
        args.getOptionValues("");
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        // 获取键值对
        args.getOptionNames().stream().forEach((option)->{
            System.out.println(option + ":" + args.getOptionValues(option));
        });
    }
}
//系统启动任务,在系统启动时执行的任务,

十八,springboot中路径映射处理

package com.example.demo.urlMaping;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/10/20 21:31
 */
@Configuration
public class WebMvcConfgi  implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 不经过Controller处理直接到视图
        registry.addViewController("/Demos").setViewName("urlMaping");
    }
}

 

十九,springboot中类型转换的处理
 

二十,springboot中的AOP实现

package com.example.demo.AOP;

import org.springframework.stereotype.Service;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/11/24 14:42
 */
@Service
public class Userservice {

    public String  getUserNameById( Integer id){
        return "嗯,执行方法";
    }
    public  String  deleteUserById(Integer id){
        return "deleteUserById";
    }

}
package com.example.demo.AOP;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/11/24 14:42
 */
@RestController
public class UserController {

    @Autowired
    Userservice userservice;


    @GetMapping("/test1")
    public String getUserNameById(Integer id){
        return userservice.getUserNameById(id);
    }

    @GetMapping("/test2")
    public String deleteUserById(Integer id){
        return userservice.deleteUserById(id);
    }
}
package com.example.demo.AOP;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/11/24 14:54
 */

@Component
@Aspect
public class LogComponent {

    @Pointcut("execution( * com.example.demo.AOP.*.*(..))")
    public void pe1(){
    }
    // 前置通知
    @Before(value = "pe1()")
    public  void before(JoinPoint jp){
        String name = jp.getSignature().getName();
        System.out.println("前置通知" + name);
    }
    // 后置通知
    @After(value = "pe1()")
    public void after(JoinPoint jp){
        String name = jp.getSignature().getName();
        System.out.println(  "后置通知" + name);
    }
    // 后置返回通知
    @AfterReturning(value = "pe1()", returning = "result")
    public void afterReturning(JoinPoint jp, Object result){
        String name = jp.getSignature().getName();
        System.out.println("后置返回通知:" + name  );
    }
    @AfterThrowing(value = "pe1()", throwing = "e")
    public void afterThrow(JoinPoint jp, Exception e){
        String name = jp.getSignature().getName();
        System.out.println("异常通知:" + name +":"+ e.getMessage());
    }
   // 环绕通知
    @Around("pe1()" )
    public  Object around(ProceedingJoinPoint pjp) throws Throwable{
        //前置
        System.out.println("环绕前---------------");
        Object proved  = pjp.proceed();
        //后置
        System.out.println("环绕后----------------");
        return "liruilong";
    }

}

 

https://tool.lu/favicon/
  • 参考博客:https://www.cnblogs.com/williamjie/p/9369878.html
  • 参考博客:http://springboot.javaboy.org/2019/0416/spring-boot-yaml
  • 参考博客:https://www.cnblogs.com/itdragon/p/7750903.html

项目实战:

Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法

romise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

let p = new Promise(function(resolve, reject){
		//做一些异步操作
		setTimeout(function(){
			console.log('执行完成Promise');
			resolve('要返回的数据可以任何数据例如接口返回数据');
		}, 2000);
	});

resolve是对promise成功时候的回调,它把promise的状态修改为fullfiled,

reject就是失败的时候的回调,他把promise的状态修改为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调。

function promiseClick(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //生成1-10的随机数
				console.log('随机数生成的值:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('数字太于10了即将执行失败回调');
				}
			}, 2000);
		   })
		   return p
	   }
 
	promiseClick().then(
		function(data){
			console.log('resolved成功回调');
			console.log('成功回调接受的值:',data);
		}, 
		function(reason, data){
			console.log('rejected失败回调');
			console.log('失败执行回调抛出失败原因:',reason);
		}
	);	

以上代码:调用promiseClick方法执行,2秒后获取到一个随机数,如果小于10,我们算成功,调用resolve修改Promise的状态为fullfiled。否则我们认为是“失败”了,调用reject并传递一个参数,作为失败的原因。并将状态改成rejected

运行promiseClick并且在then中传了两个参数,这两个参数分别是两个函数,then方法可以接受两个参数,第一个对应resolve的回调,第二个对应reject的回调。(也就是说then方法中接受两个回调,一个成功的回调函数,一个失败的回调函数,并且能在回调函数中拿到成功的数据和失败的原因),所以我们能够分别拿到成功和失败传过来的数据就有以上的运行结果


nodejs:

同样nodejs的作用和jvm的一样一样的,也是js的运行环境,不管是你是什么操作系统,

只要安装对应版本的nodejs,那你就可以用js来开发后台程序。

axios 简介:

axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:

  • 浏览器中创建XMLHttpRequests
  • 从node.js中创建http请求
  • 支持Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防御XSRF

// 为给定 ID 的 user 创建请求
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

// 可选地,上面的请求可以这样做
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });


axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
axios({
  methods: 'post',
  url: 'http://jsonplaceholder.typicode.com/users',
  data: {
  name: 'qiurx'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  })

function getUserAccount() {
  return axios.get('/user/12345');   //请求1
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');   //请求2
}

axios.all([getUserAccount(), getUserPermissions()])   //两个请求放到数组中传递给all()
  .then(axios.spread(function (acct, perms) {   //多个请求都发送完毕,拿到返回的数据
    // 两个请求现在都执行完成
  }));

 

你可能感兴趣的:(springboot)