前言
springboot: springboot整合了所有框架,并默认配置了很多框架的使用方式。
本文主要是从实际开发的角度来写springboot相关的内容,当前并未更新完,会持续更新。
1.模块一
1. 基础依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- spring-boot-starter
- springboot场景启动器,帮我们导入模块正常运行所依赖的组件
- springboot会将所有的功能场景都抽取出来,做成一个个starter,只需要在项目中引入starter,相关的所有依赖都会自动导入
2. SpringBootApplication注解
@SpringBootApplication
- 标注一个主程序类,说明这是一个springboot应用
- springboot运行改类的main方法来启动springboot应用
- 由三个注解构成(除去四个元注解之外):@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
-
@SpringBootConfiguration
- 标注在类上,表明这是一个springboot配置类
- 底层是@Configuration
-
@EnableAutoConfiguration
- 开启自动配置功能的注解
- 其底层由两个注解构成:
- @AutoConfigurationPackage 自动配置包
将添加该注解的类所在的package作为 自动配置package 进行管理
- @Import({AutoConfigurationImportSelector.class})
- 将 AutoConfigurationImportSelector类 导入到spring容器中
- AutoConfigurationImportSelector类 可以帮助springboot应用将所有符合条件(@Conditional)的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器
- 需要导入的组件会以全类名的方式返回,然后添加到容器中;同时会给容器中加入很多自动配置类 xxxAutoConfiguration(免去我们手动配置的过程)
- springboot会在启动的时候从类路径 META-INF/spring.factories 中获取 EnableAutoConfiguration 指定的值,将这些值自动配置导入容器中
-
@ComponentScan
- 定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中
- 默认装配标识了@Component注解的类到spring容器中
- @Component的派生注解有:@Controller、@Service、@Repository
3. Conditional注解
@Conditional
- 按照一定的条件进行判断,满足条件给容器注册bean,配置配里面的内容才生效
- 加在方法上(和@Bean搭配使用): 表明要满足对应条件,才注册此方法的组件
- 加在类上(搭配@Component使用): 表明要满足对应条件,此配置类才会生效
派生注解:
注解 | 说明 |
---|
@ConditionalOnJava | 系统的java版本符合要求 | @ConditionalOnBean | 容器中存在指定的Bean | @ConditionalOnMissingBean | 容器中不存在指定的Bean | @ConditionalOnExpression | 满足SpEL表达式指定 | @ConditionalOnClass | 系统中有指定的类 | @ConditionalOnMissingClass | 系统中没有指定的类 | @ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean | @ConditionalOnProperty | 系统中指定的属性有指定的值 | @ConditionalOnResource | 类路径下存在指定资源文件 | @ConditionalOnWebApplication | 当前是web环境 | @ConditionalOnNotWebApplication | 当前不是web环境 | @ConditionalOnJndi | JNDI存在指定项 |
5. Bean注解
@Bean
- 用于方法方法上:产生一个Bean对象,然后这个Bean对象交给Spring管理
- 产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中
- 搭配@Scope("prototype") 可以使得方法被多次调用,每次都实例一个Bean对象
- 用于注解上:在运行时提供注册
4. yml配置文件
1.格式
格式:key: value
2.加载与读取
加载配置文件:
读取配置文件:
-
类读取配置文件 @ConfigurationProperties(prefix = "xxx") tom:
name: 汤姆
num: 17.00
@PropertySource(value = {"classpath: person.yml"})
@Component
@ConfigurationProperties(prefix = "tom")
public class Tom {
private String name;
private double num;
}
-
属性读取配置文件 @Value("${xxx}") tom:
name: 汤姆
num: 17.00
@Component
public class Tom {
@Value("${tom.name}")
private String name;
@Value(@Value("#{ T(java.lang.Math).random() * 100.0 }"))
private String age;
}
3.profile
在实际项目中,配置文件可能会有多个,如下图,这时候就需要通过spring.profile.active指定生效的文件了
spring:
profiles:
active: dev,datasource,websecurity,token
4.加载
配置文件的加载优先级(从高到低): springboot启动后会扫描application.properties或者application.yml文件作为springboot的默认配置文件
- file: ./config/
- file:./
- classpath:/config/
- classpath:./
5. Slf4j日志
依赖:
<!--提供Slf4j日志-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
使用:
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class LogDemo {
public static String test() {
logger.trace("trace日志");
logger.debug("debug日志");
logger.info("info日志");
logger.warn("warn日志");
logger.error("error日志");
return "日志系统";
}
}
2.模块二
1. json接口
1. 代码实例
代码:
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/boot")
public class Controller {
@PostMapping("/chgGend")
public Object chgGend(@RequestBody Map<String, Object> params) {
Object gend = params.get("gend");
if (gend.equals("1")) {
params.put("gend", "男");
} else if (gend.equals("0")) {
params.put("gend", "女");
} else {
params.put("gend", "性别未知");
}
return params;
}
@PostMapping("/chgName")
public Map<String, Object> chgName(
@RequestParam(value = "gend", required = false, defaultValue = "男") String gend,
@RequestParam("name") String name) {
Map<String, Object> res = new HashMap<>();
String resName = name == "张三" ? "法外狂徒" : name;
res.put("name", resName);
res.put("gend", gend);
return res;
}
}
接口测试:
2. RequestBody注解和RequestParam注解
@RequestBody
- 主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的)
- 一般都用POST方式进行提交
- 一个请求,只有一个RequestBody
- 可以和@RequestParam()同时使用
@RequestParam
- 获取请求中的参数(不支持post请求)
- value 请求中的参数名
- required 是否必传该参数
- defaultValue 当请求中没有传递该参数的时候的默认值(需要与required 搭配使用)
两者对比:
注解 | 支持的类型 | 支持的请求类型 | 支持的Content-Type | 请求示例 |
---|
@RequestParam | url | GET | 所有 | chgName?name=张三 | @RequestBody | Body | POST/PUT/DELETE/PATCH | json | {“name”: “张三”} |
2.Filter
1.代码实例
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@Slf4j
@Order(1)
@WebFilter(urlPatterns = "/*")
public class RequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("过滤器初始化......");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("过滤器执行......");
chain.doFilter(request, response);
}
@Override
public void destroy() {
log.info("过滤器销毁......");
}
}
记得在主程序上加上注解@ServletComponentScan ,不然过滤器无法生效。
启动项目,过滤器初始化: 发送请求,过滤器执行: 结束程序,过滤器销毁:
2. 小结
-
过滤器工作流程: -
注解: @WebFilter(urlPatterns = "/*")
- 将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器
- 常用属性
- urlPatterns 指定一组过滤器的url匹配模式
- value等同于urlPatterns,但两者不能同时使用
- servletNames 指定过滤器将应用于哪些servlet
以上三个属性,至少得使用一个
- initParams 指定一组过滤器初始化参数
@Order(1)
- 设置过滤器的优先级,数值越小,优先级越高
-
方法:
-
init
- 初始化过滤器,可以在init()方法中获取Filter中的初始化参数
- 只在应用启动的时候执行一次
-
doFilter
- 完成过滤操作,当请求发过来的时候,过滤器将执行doFilter方法
- 每次发送请求都会执行
-
destroy
- Filter对象创建后会驻留在内存,当web应用移除或服务器停止时调用destroy()方法进行销毁
- 仅执行一次,执行后可以释放过滤器占用的资源
3.在配置类中注册filter
public class RequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("过滤器初始化......");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("过滤器执行......");
chain.doFilter(request, response);
}
@Override
public void destroy() {
log.info("过滤器销毁......");
}
}
import com.example.sb_demo.common.filter.RequestFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebConfiguration {
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new RequestFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.addInitParameter("paramName", "paramValue");
registrationBean.setName("RequestFilter");
registrationBean.setOrder(1);
return registrationBean;
}
}
可以在配置类中注册多个过滤器,通过setOrder 指定其优先级,如下:
@Bean
public FilterRegistrationBean filterRegistrationBean1() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new RequestFilter());
...
registrationBean.setOrder(1);
return registrationBean;
}
@Bean
public FilterRegistrationBean filterRegistrationBean1() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new AnotherFilter());
...
registrationBean.setOrder(2);
return registrationBean;
}
3. Interceptor
拦截器类(implements HandlerInterceptor ):
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("执行了拦截器的preHandle方法");
String userName = request.getParameter("name");
Object password = request.getParameter("password");
if (userName.equals("张三") && password.equals("123456")) {
log.info("身份验证通过");
return true;
}
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("执行了拦截器的postHandle方法");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("执行了拦截器的afterCompletion方法");
}
}
WebMvcConfig(implements WebMvcConfigurer )
import com.example.sb_demo.common.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration registration = registry.addInterceptor(new LoginInterceptor());
registration.addPathPatterns("/boot/**");
}
}
测试:
1. 代码实例
2. 小结
过滤器与拦截器的执行流程:
拦截器的运行流程:
拦截器(Interceptor):类似于filter,都是面向切面编程。
-
preHandler 在 Interceptor 类中最先执行,用来进行一些前置初始化操作或是对当前请求做预处理,也可以进行一些判断来决定请求是否要继续进行下去
- 返回 false,请求结束,后续的 Interceptor 和 Controller 都不会再执行
- 返回 true,继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会调用当前请求的 Controller 方法
-
postHandler 在当前请求处理完成之后,也就是 Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,可以对 Controller 处理之后的 ModelAndView 对象进行操作 -
afterCompletion 在当前对应的 Interceptor 类的 postHandler 方法返回值为 true 时才会执行,在 DispatcherServlet 渲染了对应的视图之后执行,主要用来进行资源清理
4. 整合mybatis-plus
前言
- 此部分只演示自定义SQL的查询(也就是用mybatis-plus来写mybatis,因为我这样我就不用再写springboot集成mybatis了,毕竟mybatis-plus只是对于mybatis的扩展)
- 想深入了解springboot集成mybatis-plus的一些特性和操作,请移步我的这篇文章:MyBatis-Plus
1.依赖 + yml配置
依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.11</version>
</dependency>
配置:
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo1?serverTimezone=GMT&characterEncoding=utf-8&useSSL=false
username: root
password: admin
mybatis-plus:
type-aliases-package: com.example.mp_demo.pojo
mapper-locations: classpath:/mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
server:
port: 8080
实体类:
import java.io.Serializable;
import lombok.Data;
@Data
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
private String status;
private String gender;
}
2.ResultBean
package com.example.mp_demo.common.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class ResultBean <T> implements Serializable {
private static final long serialVersionUID = 1L;
public static final int SUCCESS = 1;
public static final int FAIL = -1;
public static final int NO_LOGIN = -2;
public static final int NO_PERMISSION = -3;
private int code = SUCCESS;
private String message = "success";
private transient T data;
public ResultBean(){
super();
}
public ResultBean(T data){
super();
this.data = data;
}
public boolean isSuccess() {
return SUCCESS == this.code;
}
}
3.mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mp_demo.mapper.UserMapper">
<select id="getAll" resultType="user">
select
id,
name,
age,
status,
gender
from
user
where
status = '1'
</select>
</mapper>
4.UserMapper接口
package com.example.mp_demo.mapper;
import com.example.mp_demo.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import java.util.Map;
@Mapper
public interface UserMapper extends BaseMapper<User> {
List<User> getAll();
}
5.UserService
package com.example.mp_demo.service;
import com.example.mp_demo.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
import java.util.Map;
public interface UserService extends IService<User> {
List<User> getAll();
}
package com.example.mp_demo.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mp_demo.pojo.User;
import com.example.mp_demo.service.UserService;
import com.example.mp_demo.mapper.UserMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService{
@Resource
private UserMapper userMapper;
@Override
public List<User> getAll() {
return userMapper.getAll();
}
}
6.controller
package com.example.mp_demo.controller;
import com.example.mp_demo.common.entity.ResultBean;
import com.example.mp_demo.pojo.User;
import com.example.mp_demo.service.UserService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("user")
public class UserController {
@Resource
private UserService userService;
@RequestMapping("getAll")
public ResultBean getAll() {
ResultBean resultBean = new ResultBean();
List<User> data = userService.getAll();
if (!data.isEmpty()) {
resultBean.setCode(ResultBean.SUCCESS);
resultBean.setData(data);
resultBean.setMessage("成功获取数据");
} else {
resultBean.setCode(ResultBean.FAIL);
resultBean.setMessage("获取数据失败");
}
return resultBean;
}
}
测试: 不需要传参数。
3.模块三
未完待续…
|