springboot

回顾spring

  • 轻量级的:指的是spring核心功能的jar包不大。
  • 非侵入式的:业务代码不需要继承或实现spring中任何的类或接口
  • IOC:控制反转(Inverse of Control),以前项目都是在哪儿用到对象,在哪儿new,把生成对象的权利反转给spring框架,可以对对象进行功能的增强(让spring把对象管理起来,在哪用在哪注入)
  • AOP:面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。

缺点:

  • 配置非常麻烦,且配置模板化(都一样的)
  • 需要开发人员添加许多的依赖,且依赖之间的版本不好控制

SpringBoot对以上spring的两个缺点进行补充,主要是对spring框架的搭建进行封装简化。不是说就不需要配置了,只是换了一种方式进行配置,并把许多模板化配置直接整合了。

springBoot是基于spring框架,对spring框架的搭建进行封装,不是代替spring,spring的核心功能不变的。可以快速搭建,并集成其他的框架和组件。

约定(大家公认的一种做法)大于配置的核心思想

SpringBoot特点

  1. 创建独立的spring应用程序。
  2. 直接内嵌 tomcat(一个项目就是一个服务,就是微服务的思想)、jetty 和 undertow
  3. 提供了固定化的"starter"配置,以简化构建配置,尽可能的自动配置spring和第三方库。
  4. 提供产品级的功能,如:安全指标、运行状况监测和外部化配置等。
  5. 绝对不会生成代码,并且不需要 XML 配置,提供了另外一种方式进行配置。
搭建

一个基于springboot的spring应用程序

1.去官方选择配置 https://start.spring.io/

springboot_第1张图片

2.选择配选项,在线生成并下载。解压后修改 pom.xml 版本为 2.6.6,删除mvn 文件夹、mvnw.cmd 文件下载,解压 修改pom.xml,删除不需要的文件。

3.导入到idea。选择Open or Import

4.开发一个controller(spring、springweb直接集成搭建好)

package com.ffyc.news.web;

@RestController
@RequestMapping(path = "loginCtl")
public class LoginController {

    @RequestMapping(path = "/test")
    public String test(){
        System.out.println("hello");
        return "hello";
    }
}

5.ip:端口/控制地址/方法地址。

127.0.0.1:8080/loginCtl/test,访问8080就是访问这个项目

@SpringBootApplication
public class NewsApplication {
	/*spring应用程序的启动类, 必须放置在其他类的上一级包中
	@ComponentScan() 扫描本包中所有的类*/
	public static void main(String[] args) {
		SpringApplication.run(NewsApplication.class, args);
	}
}

springBoot 的核心功能

  1. 起步依赖:会把项目中使用到的相关的组件自动依赖进来(json,日志...)
  2. 自动配置springboot会根据项目中依赖的相关组件,在启动时,自动创建并初始化。配置web,启动时就会自动的去加载web相关的组件,例如DispatcherServlet(约定大于配置)。

spring Boot 配置文件

Spring Boot 使用一个全局的配置文件(配置文件名是固定的

1.application.properties 属性文件格式,键值对存储数据,把配置文件中的值都存放在此文件中

server.port=8080 

2.application.yml ,yml 是 yaml(YAML Ain’t Markup Language)语言的文件,以数据为中心。

yml 配置示例:

#配置内置服务器的端口号
server:
  port: 9999

key:空格value 以此来表示一对键值对(空格不能省略);以空格的缩进来表示层级关系,只要是左边对齐的一列数据都是同一个层级的。

值的写法:

  • 字面量:普通的值[数字,布尔值,字符串]
  • 字面量直接写在后面就可以,字符串默认不用加上双引号或者单引号;

案例:

user:
  name: zhangsan
  age: 20 

使用@Value 注解标签将配置文件中的内容映射到类中的属性。@Value("${user.name}")

springboot添加spring中的jdbc模块

功能:1.提供了JdbcTemplate 2.事务管理(重点)

1.为了连接数据库需要引入 jdbc 支持,在 pom.xml 中引入如下配置:


    org.springframework.boot
    spring-boot-starter-jdbc


    mysql
    mysql-connector-java
    8.0.16

2.在 application.yml 中配置数据源信息

spring:
  #配置数据库的链接库信息,生成默认的数据源对象,并生成jdbcTemplate,事务管理功能都会进行初始化
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/ssmdb?serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

3.测试

@RestController
@RequestMapping(path = "/loginCtl")
public class LoginController {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Transactional
    @RequestMapping(path = "/test")
    public String test(){
        jdbcTemplate.execute("insert into admin(account)values ('aaaaaaaaaa')");
        System.out.println(10/0);
        jdbcTemplate.execute("insert into admin(account)values ('bbbbbbbbbb')");
        System.out.println("hello");
        return "hello";
    }
}
springBoot 整合阿里数据源

1.导入阿里数据源 jar



    com.alibaba
    druid
    1.1.10

2.在 yml 文件中注册阿里数据库连接池

  • Size: 5 初始化时建立物理连接的个数
  • minIdle: 1 最小连接池数量
  • maxActive: 20 最大连接池数量
spring:
  #配置数据库的链接库信息,生成默认的数据源对象,并生成jdbcTemplate,事务管理功能都会进行初始化
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/ssmdb?serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource #指定数据源类型,还需要创建DruidDataSource对象
    initialSize: 5 #数据库连接池相关的配置
    maxActive: 20
    minIdle: 1

3.添加配置类,生成DruidDataSource对象类

//配置注解,表示此类是springBoot项目中一个配置类,sprngboot启动时会扫描
@Configuration
public class DruidDataSourceConfig {
	//@Bean  ==   作用在方法上,方法中会产生一个对象,最终把此对象交给spring容器

	@Bean
	@ConfigurationProperties(prefix = "spring.datasource")
	public DataSource druid() {
        //创建DruidDataSource对象,并从yml配置文件读取配置值,赋值
		DruidDataSource  dataSource = new DruidDataSource();
		//dataSource.setInitialSize();
		return dataSource;
	}
}
springBoot 集成 mybatis

1.导入jar


    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    2.1.4

2.在application.yml文件中配置mybatis

#mybatis配置,创建sqlsessionFactory
mybatis:
  type-aliases-package: com.ffyc.news.model
  mapper-locations: classpath:mappers/*Mapper.xml
  configuration: #mybatis中settings配置
    map-underscore-to-camel-case: true #mysql和java的驼峰对应
    cache-enabled: true #缓存

3.启动类上添加@MapperScan("接口所在的包地址"),或者在接口上添加@Mapper

@SpringBootApplication
@MapperScan("com.ffyc.news.dao") //扫描接口所在的包,生成接口的代理对象
public class NewsApplication {
	/*spring应用程序的启动类, 必须放置在其他类的上一级包中
	@ComponentScan() 扫描本包中所有的类*/
	public static void main(String[] args) {
		SpringApplication.run(NewsApplication.class, args);
	}
}
@RestController
@RequestMapping(path = "/loginCtl")
public class LoginController {

    @Autowired
    LoginService loginService;

    @Transactional
    @RequestMapping(path = "/login")
    public String login(){
        loginService.login(new Admin());
        return "hello";
    }
}
@Service
@Transactional
public class LoginService {
    @Autowired
    LoginDao loginDao;
    public Admin login(Admin admin){
        Admin admin1=loginDao.login(admin);
        return admin1;
    }
}
@Repository
public interface LoginDao {
    Admin login(Admin admin);
}

    

springboot中的注解标签

1.@SpringBootApplication:springboot中最核心注解标签,是一个组合注解标签,里面包含3个:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan

2.@Configuration:作用在类上面,表明此类是一个配置类,启动时就会自动的去加载

@Bean:作用在方法上,此方法会返回一个对象,交给spring框架管理

@Configuration//配置注解,表示此类是springBoot项目中一个配置类,sprngboot启动时会扫描
public class DruidDataSourceConfig {
    
//@Bean ==  作用在方法上,此方法产生的对象,最终返回并交给spring容器管理
	@Bean
	@ConfigurationProperties(prefix = "spring.datasource")
	//创建DruidDataSource对象,并从yml配置文件读取配置值,赋值
	public DataSource druid() {
		DruidDataSource  dataSource = new DruidDataSource();
		//dataSource.setInitialSize();
		return dataSource;
	}
}

@Bean等同于这个:



    
    
    
    
    
    

3.@ConfigurationProperties(prefix = "spring.datasource") 可以将application.yml文件中的内容读取到,并赋给对应的属性

@Value("${user.name}") 可以将application.yml文件中的内容读取到,并赋给对应的属性

filePath:
  path1: D:/
  path2: E:/
@SpringBootTest
class NewsApplicationTests {

	@Value("${filePath.path1}")
	String path1;
	@Value("${filePath.path2}")
	String path2;

	@Test
	void contextLoads() {
		System.out.println(path1+"::"+path2);
	}
}

验证token的拦截器

package com.ffyc.news.common;

import com.fasterxml.jackson.databind.json.JsonMapper;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//token验证的拦截器
public class Token implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String adminToken=request.getHeader("adminToken");
        boolean res=JWTUtil.verify(adminToken);
        if(!res){
            CommonResult commonResult=new CommonResult(401,"token失效");
            JsonMapper jsonMapper=new JsonMapper();
            String json=jsonMapper.writeValueAsString(commonResult);
            response.getWriter().print(json);
        }
        return res;
    }
}
package com.ffyc.news.common;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;

@Configuration
public class WebConfig implements WebMvcConfigurer{

	public void addInterceptors(InterceptorRegistry registry) {
		InterceptorRegistration inter =  registry.addInterceptor(new Token());
		inter.addPathPatterns("/admin/**"); //管理员需要拦截过滤地址
		inter.excludePathPatterns("/admin/loginCtl/login");//放行地址
	}
}

springboot解决跨域

package com.ffyc.news.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Collections;
@Configuration
public class CorsConfig {
    //跨域配置
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //1,允许任何来源
        corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));
        //2,允许任何请求头
        corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
        //3,允许任何方法
        corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
        //4,允许凭证
        corsConfiguration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(source);
    }
}

统一异常处理

一旦web层出现异常,就会被globalException拦截到

package com.ffyc.news.common;

//使用面向切面的思想,将Controller层中所出现的异常进行统一的捕获
@RestControllerAdvice
public class GlobalExceptionHandler {
    //统一异常处理
    @ExceptionHandler(Exception.class)
    public CommonResult globalException(Exception e) {
        System.out.println("aaaaa"+e.getMessage());
        CommonResult commonResult = new CommonResult(500,e.getMessage());
        return commonResult;
    }
}

项目中集成日志功能

最早调式程序:使用System.out.println(res); 直观的看到结果,跟踪程序运行过程。

1.为什么要在程序中添加日志功能?

日志记录:记录程序执行过程的痕迹。不能是使用System.out.println(res);输出,平常练习可以,正式环境没有控制台。最好是将程序运行中的必要的数据,输出到一个文件中,做到长久保存日志文件。

主要是为了方便我们监测生产环境的变量值变化以及代码运行轨迹等,记录生产环境中的值(入参,返回值),运行到了哪个方法(位置),将信息输出到文件中,对于分析锁定问题有很好的帮助。

2.如何快速的实现日志功能

将日志信息输出到文件中,在市面上有很多的日志组件,可以帮助我们快速的实现日志功能。

常见的日志组件:

  • slf4j
  • commons-logging
  • Log4J
  • Logback

前两个是日志上层功能定义的接口,后两个主要是底层的实现。一般首选强烈推荐使用 slf4j + logback,在spring依赖中已经集成了。

提供的日志组件功能就更加的全面,例如: 将日志分为不同的等级,可以在不同的情况下,输出不同等级的日志信息

从低到高:debug(开发,练习)

  • debug 包含debug,以及以上的日志都可以输出
  • info 包含info,以及以上的日志都可以输出
  • warn 包含warn,error
  • error 只输出error

1.在类中使用

#日志配置
logging:
  level:
    com.ffyc.news: debug  #日志级别
  file:
    name: E:/log/log.log  #日志位置
@RestController
@RequestMapping(path = "/admin/loginCtl")
public class LoginController {

    //创建logger对象(slf4j中的)
    static Logger logger= LoggerFactory.getLogger(LoginController.class);

    @Autowired
    LoginService loginService;

    //后端可以接收前端提交的json数据,但是必须是对象接收,必须在参数的前面添加@RequestBody
    @RequestMapping(path = "/login")
    public CommonResult login(@RequestBody Admin admin){
        //在需要的位置调用具体的日志级别方法输出
        logger.debug("进入到后端登录功能:account={},password={}",admin.getAccount(),admin.getPassword());
        logger.info("进入到后端登录功能:account={},password={}",admin.getAccount(),admin.getPassword());
        logger.warn("进入到后端登录功能:account={},password={}",admin.getAccount(),admin.getPassword());
        logger.error("进入到后端登录功能:account={},password={}",admin.getAccount(),admin.getPassword());
        Admin a=loginService.login(admin);
        logger.debug("登录完成:account={},password={}",a.getAccount(),a.getPassword());
        if(a!=null){
            return new CommonResult(200,a,"登录成功");
        }
        return new CommonResult(201,"账号或密码错误");
    }
}

2.SpringBoot使用AOP统一打印日志

导入依赖 jar


    org.springframework.boot
    spring-boot-starter-aop

定义切面通知类

package com.ffyc.news.common;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

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

@Component
@Aspect
public class LogAspect {
    private Logger logger = LoggerFactory.getLogger(getClass());
    //通配符,定义规则,哪些方法可以被我的切面切到,这里的意思是不限返回值和方法和参数
    @Pointcut("execution(public * com.ffyc.news.web..*.*(..))")
    public void webLog() {
    }
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        logger.info("HTTP_METHOD :{} ", request.getMethod());
        logger.info("IP : {}", request.getRemoteAddr());
        //获取所有请求参数
        Enumeration enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String name = (String) enu.nextElement();
            logger.info("name:{},value:{}", name, request.getParameter(name));
        }
    }
    /*@AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfter(Object ret) throws Throwable {
        // 处理完请求,返回内容
        logger.info("RESPONSE : " + ret);
    }*/
}

Swagger组件

现在前后端都是自己在进行开发,前端向后端提交什么数据,后端向前端返回什么数据都是知道的。但是前后端实际开发中,是由不同的人员进行开发的,需要后端开发人员向前端开发人员提供一个说明文档,后期有可能要修改文档,重新发送给前端开发人员。 现在有很多的一些组件,可以帮助我们来在线生成API文档,在类或方法上添加一些注解标签,就可以生成文档,修改后会自动的更新。

但是前后端实际开发中,是由不同的人员进行开发的。

需要后端开发人员向前端开发人员提供一个说明文档

登录

接口功能:登录

接口地址:/admin/loginCtl/login

提交数据:请求头: token 请求体: account: password:

返回状态码:200成功、500报错 201 202

Swagger功能:

  • 支持API自动生成同步的在线文档:使用 Swagger 后可以直接通过代码生成文档,不再需要自己手动编写接口文档了,对程序员来说非常方便,可以节约写文档的时间去学习新技术。
  • 提供Web页面在线测试API:光有文档还不够,Swagger 生成的文档还支持在线测试。参数和格式都定好了,直接在界面上输入参数对应的值即可在线测试接口。
搭建

1.导入 jar


    io.springfox
    springfox-swagger2
    2.9.2


    io.springfox
    springfox-swagger-ui
    2.9.2

2.在 application.yml 中配置

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

3.添加 swagger 配置类

  • 配置 swagger 扫描方式
package com.ffyc.news.config;

import io.swagger.annotations.Api;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    /**
     * 创建API应用
     * apiInfo() 增加API相关信息
     * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
     * 本例采用指定扫描的包路径来定义指定要建立API的目录。
     * @return
     */
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .enable(true)
                .select()
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * 创建该API的基本信息(这些基本信息会展现在文档页面中)
     * 访问地址:http://项目实际地址/swagger-ui.html
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Spring Boot中使用Swagger2构建RESTful APIs")
                .description("更多请关注http://www.baidu.com")
                .termsOfServiceUrl("http://www.baidu.com")
                .contact(new Contact("a", "b", "c"))
                .version("1.0")
                .build();
    }
}
  • 及放行静态资源请求不被 spring 拦截

web层配置 /,所有访问后端的请求,都会进入到DispatcherServLet,swagger组件生成的api是网页格式的,是在后端生成的,势必就会访问后端swagger的html页面。访问swagger-ui.html时,就会被DispatcherServlet拦截,所以需要配置访问swagger相关页面时,不让其进入到DispatcherServLet

package com.ffyc.news.common;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;

@Configuration
public class WebConfig implements WebMvcConfigurer{

    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration inter =  registry.addInterceptor(new Token());
        inter.addPathPatterns("/admin/**"); //管理员需要拦截过滤地址
        inter.excludePathPatterns("/admin/loginCtl/login");//放行地址

        //放行行前台首页,文章详细信息等地址
        inter.excludePathPatterns("/swagger*/**"); //放行swagger
        inter.excludePathPatterns("/v2/**");//放行swagger
        inter.excludePathPatterns("/webjars/**");//放行swagger
    }

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("swagger-ui.html").addResourceLocations(
				"classpath:/META-INF/resources/");
		registry.addResourceHandler("/webjars/**").addResourceLocations(
				"classpath:/META-INF/resources/webjars/");
	}
}
Swagger 使用的注解及其说明

主要用在控制器类和model类上面

1、@Api(tags="类的功能描述"):用在类上,说明该类的作用

springboot_第2张图片

2、@ApiOperation(value="方法概述", notes="功能详细描述"):用在方法上,用于对方法功能说明

springboot_第3张图片

3、@ApiImplicitParam:用来注解来给方法入参增加说明。

paramType 属性表示参数放在哪里,主要有以下几个属性:

  • header-->放在请求头。请求参数的获取:@RequestHeader(代码中接收注解)
  • query-->用于 get 请求的参数拼接。请求参数的获取
  • path(用于 restful 接口)-->请求参数的获取:@PathVariable(代码中接收注解)
  • body-->放在请求体。请求参数的获取:@RequestBody(代码中接收注解)

4、参数为实体类时,在实体类上添加注解

  • @ApiModel:描述一个Model类的信息(参数为实体类时使用)
  • @ApiModelProperty:描述一个 model 的属性

springboot_第4张图片

springboot_第5张图片

你可能感兴趣的:(spring,boot,后端,java)