缺点:
SpringBoot对以上spring的两个缺点进行补充,主要是对spring框架的搭建进行封装简化。不是说就不需要配置了,只是换了一种方式进行配置,并把许多模板化配置直接整合了。
springBoot是基于spring框架,对spring框架的搭建进行封装,不是代替spring,spring的核心功能不变的。可以快速搭建,并集成其他的框架和组件。
约定(大家公认的一种做法)大于配置的核心思想
一个基于springboot的spring应用程序
1.去官方选择配置 https://start.spring.io/
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 的核心功能
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}")
功能: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";
}
}
1.导入阿里数据源 jar
com.alibaba
druid
1.1.10
2.在 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
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;
}
}
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);
}
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);
}
}
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");//放行地址
}
}
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); 直观的看到结果,跟踪程序运行过程。
日志记录:记录程序执行过程的痕迹。不能是使用System.out.println(res);输出,平常练习可以,正式环境没有控制台。最好是将程序运行中的必要的数据,输出到一个文件中,做到长久保存日志文件。
主要是为了方便我们监测生产环境的变量值变化以及代码运行轨迹等,记录生产环境中的值(入参,返回值),运行到了哪个方法(位置),将信息输出到文件中,对于分析锁定问题有很好的帮助。
将日志信息输出到文件中,在市面上有很多的日志组件,可以帮助我们快速的实现日志功能。
常见的日志组件:
前两个是日志上层功能定义的接口,后两个主要是底层的实现。一般首选强烈推荐使用 slf4j + logback,在spring依赖中已经集成了。
提供的日志组件功能就更加的全面,例如: 将日志分为不同的等级,可以在不同的情况下,输出不同等级的日志信息
从低到高:debug(开发,练习)
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);
}*/
}
现在前后端都是自己在进行开发,前端向后端提交什么数据,后端向前端返回什么数据都是知道的。但是前后端实际开发中,是由不同的人员进行开发的,需要后端开发人员向前端开发人员提供一个说明文档,后期有可能要修改文档,重新发送给前端开发人员。 现在有很多的一些组件,可以帮助我们来在线生成API文档,在类或方法上添加一些注解标签,就可以生成文档,修改后会自动的更新。
但是前后端实际开发中,是由不同的人员进行开发的。
需要后端开发人员向前端开发人员提供一个说明文档
登录
接口功能:登录
接口地址:/admin/loginCtl/login
提交数据:请求头: token 请求体: account: password:
返回状态码:200成功、500报错 201 202
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 配置类
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();
}
}
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/");
}
}
主要用在控制器类和model类上面
1、@Api(tags="类的功能描述"):用在类上,说明该类的作用
2、@ApiOperation(value="方法概述", notes="功能详细描述"):用在方法上,用于对方法功能说明
3、@ApiImplicitParam:用来注解来给方法入参增加说明。
paramType 属性表示参数放在哪里,主要有以下几个属性:
4、参数为实体类时,在实体类上添加注解