SpringBoot
基于SpringFramework进行二次开发的一个web快速开发框架(创建,编写项目等)
创建项目
-
去官网创建Spring Initializr (springboot.io)
-
用idea开发工具创建
什么是配置文件?用途是什么?
保存了很多配置参数的
配置文件
-
xxx.properties 配置参数:key=value键值对
-
xxx.yml 配置参数JSON:key:value
-
application.properties,application.yml配置参数文件
-
bootstrap.properties,bootstrap.yml是项目引导文件
多环境的配置
- 开发环境
- 测试环境
- 预生产环境
- 生成环境
IOC容器
- 基于注解@Component (@ComponentScan basepackage)
- @Configurtion
- @XML Bean
//元注解
@Target({ElementType.TYPE})//生效范围
@Retention(RetentionPolicy.RUNTIME)//声明周期1.源码阶段有效2.编译阶段有效3.运行阶段有效
@Documented
@Inherited
@SpringBootConfiguration
@SpringBootConfiguration->@Configuration配置类==xml
配置文件的注解
@EnableAutoConfiguration
自动配置关键注解->spring.factories
先把类的全路径写在一个配置文件,然后用反射机制创建对象,把对象塞进ioc容器
约定优于配置 配置优于编码
常用注解
@SpringBootApplication //Boot应用启动类 @SpringBootConfiguration//申明boot配置类 =@Configuration配置类==xml @EnableAutoConfiguration //开启自动配置 @ConfigurationProperties //批量配置参数 @Value //注入参数 @Configuration //申明配置类 @ComponentScan //组件扫描 @RequestMapping //定义请求路径 @GetMapping //定义GET请求路径 @PostMapping //定义POST请求路径 @Controller //申明控制类 @RestController //申明restful风格控制类 @Service //申明业务逻辑类 @Component //定义组件类(Bean) @RequestParam //绑定请求参数 @RequestBody //JSON格式获取HTTP 请求BODY部分数据 @Resource //自动装配对象 java @Autowired //自动装配对象 spring @PathVariable //从路径上获取占位符对应参数 @Mapper //mybatis 数据处理接口 @Bean //定义 JavaBean @JsonIgnore//忽略某个字段,不展示给前端
- @SpringBootApplication //boot应用启动类
- @SpringBootConfiguration //申明boot配置类==@Configuration
- @EnableAutoConfiguration //开启自动配置
- @ConfigurationProperties //批量配置参数
- @Value //配置参数值
- @Configuration //申明配置类
- @ComponentScan //组件扫描
- @RequestMapping //定义请求路径
- @GetMapping //定义get请求路径
- @PostMapping //定义post请求路径
- @Controller //申明控制类
- @RestController 申明restful风格控制类
- @Service //申明业务逻辑类
- @Component //定义组件类
- @RequestParam //绑定请求参数
- @RequestBody //JSON格式获取HTTP请求BODY部分数据
- @Resource //自动装配对象 Java
- @Autowired //自动装配对象spring
- @PathVariable //从路径上获取占位符对应参数
- @Mapper //mybatis数据处理接口
- @Bean //定义javabean 注册到ioc
分析软件应用(MVC模式)
Springboot日志框架
LOGBACK
日志
软件运行过程中用于记录,执行,轨迹的代码块
日志的优点
- 能够辅助定位软件运行问题
- 提供统计数据
以前的日志
System.out.println()
–>往控制台输出一行日志
日志级别
- trace跟踪
- debug调试
- info信息
- warn警告
- error错误
日志的格式
时间戳毫秒级 日志级别 线程ID 线程名字 执行类 日志信息
一般info级别就可以;日志也会耗时间的
日志的配置
#推荐的设置方式
#打开日志级别 默认是info
logging.level.root=warn
logging.level.web=debug
logging.level.sql=error
#打印日志信息文件
logging.file.name=s98-1026
测试
package com.spring.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LogController {
//获取日志记录器;注意导入的包名
final static Logger logger = (Logger) LoggerFactory.getLogger(LogController.class);
@RequestMapping("/showlog")
public String show() {
logger.trace("记录trace级别日志");
logger.debug("记录debug级别日志");
logger.info("记录info级别日志");
logger.warn("记录warn级别日志");
logger.error("记录error级别日志");
return null;
}
}
JWT (Json Web Token)
jwt的格式
kjsdfgkjsdfb.lshflsdhfds.lsdkhfisdlg
(头部信息.挂载部分.签名信息)
JWT用法
sadfas = encode(a.s.d,密钥(任意一个字符串))
qwrr = decode(sadfas,密钥(任意一个字符串))
JWT依赖包
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.3.0</version>
</dependency>
生成Token
package com.spring.utiltools;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Verification;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtTools {
//密钥
public static final String KEY = "qanap&#!";
//生成token(加密)
public static String createToken() {
//token生成器
JWTCreator.Builder builder = JWT.create();
//保存头部信息
Map<String, Object> claims = new HashMap<>();
claims.put("type", "HS256");
builder.withHeader(claims)
.withJWTId("1001")
.withIssuedAt(new Date());//token生效时间
Date expDate = new Date(System.currentTimeMillis()+(7*24*60*60*1000));
return builder.withExpiresAt(expDate)//token失效数据
.withClaim("attrs",attrMap)
.sign(Algorithm.HMAC256(KEY));
}
public static void main(String[] args) {
System.out.println(JwtTools.createToken());
}
}
解析Token
public static void checkToken(String token) {
//根据加密算法与密钥获取验证器
JWTVerifier require = JWT.require(Algorithm.HMAC256(KEY)).build();
DecodedJWT decodedJWT = require.verify(token);
Map<String, Claim> claims = decodedJWT.getClaims();
System.out.println(claims.get("username"));
System.out.println(claims.get("pwd"));
System.out.println(claims.get("phone"));
System.out.println(decodedJWT.getHeader());
System.out.println(decodedJWT.getExpiresAt());
System.out.println(decodedJWT.getId());
}
控制层controller
@RestController
@CrossOrigin
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
@Autowired
UserMapper userMapper;
Logger logger = LoggerFactory.getLogger(UserController.class);
@RequestMapping("/sendSMS")
public void send(@RequestParam("phone") String phone, HttpSession session) {
logger.info("phone------------>" + phone);
String yzm = SendSMSTools.sendSMS(phone);
System.out.println("---------->"+yzm);
session.setAttribute("yzm", yzm);
}
@RequestMapping("/login")
public String login(@RequestParam("phone") String phone,
@RequestParam("yzm") String yzm,
HttpSession session) {
logger.info(phone);
logger.info(yzm);
String code = session.getAttribute("yzm")+"";
logger.info("code:"+code);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("phone");
List<User> users = userMapper.selectList(queryWrapper);
if (users != null) {
for (User user : users) {
if (user.getPhone().equals(phone) ) {
logger.info("user.getPhone():"+user.getPhone());
Map<String,Object>userMap = new HashMap<>();
userMap.put("phone", phone);
userMap.put("yzm", yzm);
return JwtTools.createToken(userMap);
}
}
}
return null;
}
}
登录流程
- 提供手机号登录,发送验证码,session,redis
- 完成手机号与验证
- 颁发令牌
- 浏览器发送请求&token
- 过滤器,拦截器–拦截每一个请求,验证是否有token,如果有token验证token合法性验证通过跳转首页,验证没有token直接返回登录页面
RBAC&ABAC
用户表,权限表,角色表,用户角色表,角色权限表,菜单表,菜单权限表
RBAC:权限管理模块
–角色管理
–权限管理
- –菜单管理
- –按钮,DIV,ABAC
–用户管理
ABAC:属性权限管理模块
权限框架Sa-Token&Ruoyi
Ruoyi
官网:RuoYi
Sa-Toekn
这些是部分内容更详细的内容去官网查看
官网:Sa-Token
SaToken的依赖
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.37.0</version>
</dependency>
yml配置
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: satoken
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
timeout: 2592000
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
active-timeout: -1
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
is-share: true
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
token-style: uuid
# 是否输出操作日志
is-log: true
使用方式
两中方式都在官网官网写的很详细
API
// 会话登录:参数填写要登录的账号id,建议的数据类型:long | int | String, 不可以传入复杂类型,如:User、Admin 等等
StpUtil.login(Object id);
// 当前会话注销登录
StpUtil.logout();
// 获取当前会话是否已经登录,返回true=已登录,false=未登录
StpUtil.isLogin();
// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
StpUtil.checkLogin();
// 获取当前会话账号id, 如果未登录,则抛出异常:`NotLoginException`
StpUtil.getLoginId();
// 类似查询API还有:
StpUtil.getLoginIdAsString(); // 获取当前会话账号id, 并转化为`String`类型
StpUtil.getLoginIdAsInt(); // 获取当前会话账号id, 并转化为`int`类型
StpUtil.getLoginIdAsLong(); // 获取当前会话账号id, 并转化为`long`类型
// ---------- 指定未登录情形下返回的默认值 ----------
// 获取当前会话账号id, 如果未登录,则返回 null
StpUtil.getLoginIdDefaultNull();
// 获取当前会话账号id, 如果未登录,则返回默认值 (`defaultValue`可以为任意类型)
StpUtil.getLoginId(T defaultValue);
// 获取当前会话的 token 值
StpUtil.getTokenValue();
// 获取当前`StpLogic`的 token 名称
StpUtil.getTokenName();
// 获取指定 token 对应的账号id,如果未登录,则返回 null
StpUtil.getLoginIdByToken(String tokenValue);
// 获取当前会话剩余有效期(单位:s,返回-1代表永久有效)
StpUtil.getTokenTimeout();
// 获取当前会话的 token 信息参数
StpUtil.getTokenInfo();
注解鉴权
官网更详细:注解鉴权 (sa-token.cc)
**注意:**用注解鉴权之前必须要打开注解式功能**注册 Sa-Token拦截器,打开注解式功能**
package com.jwt.config;
import cn.dev33.satoken.interceptor.SaInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//注册 Sa-Token拦截器,打开注解式功能
@Configuration
public class PowerInterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor())
.addPathPatterns("/**");
}
}
@SaCheckLogin
: 登录校验 —— 只有登录之后才能进入该方法。@SaCheckRole("admin")
: 角色校验 —— 必须具有指定角色标识才能进入该方法。@SaCheckPermission("user:add")
: 权限校验 —— 必须具有指定权限才能进入该方法。@SaCheckSafe
: 二级认证校验 —— 必须二级认证之后才能进入该方法。@SaCheckBasic
: HttpBasic校验 —— 只有通过 Basic 认证后才能进入该方法。@SaIgnore
:忽略校验 —— 表示被修饰的方法或类无需进行注解鉴权和路由拦截器鉴权。@SaCheckDisable("comment")
:账号服务封禁校验 —— 校验当前账号指定服务是否被封禁。
@RequestMapping("/anno")
// @SaCheckLogin
@SaCheckPermission("打印")
public Object annoEx() {
return SaResult.ok("");
}
@ExceptionHandler
public Object handException(Exception e, Model model) {
e.printStackTrace();//异常堆栈
model.addAttribute("errMsg","非常抱歉:"+e.getMessage());
return "/power/500";
}
登录,注销 测试
注意事项
在sa-token 中验证有两种处理方式
- 中断式处理-以抛出异常方式处理 checkXXX
- 非中断式处理- 校验式-返回布尔值 isXXX
视图层
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="/power/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="text" style="margin-left: 15px;margin-top: 10px" name="password"><br>
<button type="submit" style="margin-top: 10px">登录</button>
<a href="/power/checkLogin" style="margin-left: 15px;">查看登录状态</a>
<a href="/power/logout" style="margin-left: 15px;">退出登录</a>
<a href="/power/checkPower" style="margin-left: 15px;">查看权限</a>
<a href="/power/checkEx" style="margin-left: 15px;">全局处理异常</a>
</form>
</body>
</html>
控制层
package com.jwt.controller;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jwt.service.UserService;
import com.jwt.vo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/power")
public class PowerController {
@Autowired
UserService userService;
@RequestMapping("/login")
public Object login(@RequestParam("username") String username,
@RequestParam("password") String password) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("uname", username)
.eq("upwd", password);
User user = userService.getOne(queryWrapper);
if (user != null) {
StpUtil.login(user.getUid());
return new SaResult(200, "", user);
}
return SaResult.error("登录失败,用户未登录");
}
@RequestMapping("/checkLogin")
public Object checkLogin() {
//在sa-token 中验证有两种处理方式
//中断式处理-以抛出异常方式处理 checkXXX
//StpUtil.checkLogin();
//非中断式处理- 校验式-返回布尔值 isXXX
if (StpUtil.isLogin()) {
return SaResult.ok("用户已登录");
} else {
return SaResult.ok("用户未登录");
}
}
@RequestMapping("/logout")
public Object logout() {
// StpUtil.logout(); //注销所有账号
// StpUtil.logout(10001); // 强制指定账号注销下线
// StpUtil.logout(10001, "PC"); // 强制指定账号指定端注销下线
// StpUtil.logoutByTokenValue("token"); // 强制指定 Token 注销下线
StpUtil.kickout(10001); // 将指定账号踢下线
StpUtil.kickout(10001, "PC"); // 将指定账号指定端踢下线
StpUtil.kickoutByTokenValue("token"); // 将指定 Token 踢下线
return SaResult.ok("");
}
}
账号封禁
更多内容在官网
// 封禁指定账号
StpUtil.disable(10001, 86400);
// 先踢下线
StpUtil.kickout(10001);
// 再封禁账号
StpUtil.disable(10001, 86400);
// 校验指定账号是否已被封禁,如果被封禁则抛出异常 `DisableServiceException`
StpUtil.checkDisable(10001);
// 通过校验后,再进行登录:
StpUtil.login(10001);
// 封禁指定账号
StpUtil.disable(10001, 86400);
// 获取指定账号是否已被封禁 (true=已被封禁, false=未被封禁)
StpUtil.isDisable(10001);
// 校验指定账号是否已被封禁,如果被封禁则抛出异常 `DisableServiceException`
StpUtil.checkDisable(10001);
// 获取指定账号剩余封禁时间,单位:秒,如果该账号未被封禁,则返回-2
StpUtil.getDisableTime(10001);
// 解除封禁
StpUtil.untieDisable(10001);
sa-token权限角色管控
实现 StpInterface
接口
package com.jwt.service.impl;
import cn.dev33.satoken.stp.StpInterface;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class RoleAndPowerServiceImpl implements StpInterface {
@Override
public List<String> getPermissionList(Object o, String s) {
//1.查询权限表-权限初始化
//2.最小化范围
//3.SQL语句带上用户ID查询权限表(重要)
List<String>list = new ArrayList<>();
list.add("添加");
list.add("删除");
list.add("修改");
list.add("查询");
return list;
}
@Override
public List<String> getRoleList(Object o, String s) {
List<String>roles = new ArrayList<>();
roles.add("普通用户");
roles.add("管理员");
roles.add("经理");
roles.add("总监");
return roles;
}
}
控制层
@RequestMapping("/checkPower")
public Object checkPower() {
//在sa-token 中验证有两种处理方式
boolean check = StpUtil.hasPermission("添加");//非中断式处理
// StpUtil.checkPermission("打印");//中断式处理
// StpUtil.checkRole("经理");
if (check) {
return SaResult.ok("此用户有这个权限");
}else {
return SaResult.ok("此用户没有这个权限");
}
// return "";
}
全局异常处理
这些注解很重要的
@RestControllerAdvice//返回的是json对象
@ControllerAdvice//跳转页面
@ExceptionHandler
定义处理异常类
(这是程序出口)
package com.jwt.handler;
import cn.dev33.satoken.util.SaResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//@Slf4j
@RestControllerAdvice//返回的是json对象
//@ControllerAdvice//跳转页面
public class PowerExceptionHandler {
@ExceptionHandler
public Object handException(Exception e) {
e.printStackTrace();//异常堆栈
return SaResult.error("非常抱歉" + e.getMessage());
}
// @ExceptionHandler
// public Object handException(Exception e, Model model) {
// e.printStackTrace();//异常堆栈
// e.getMessage().contains("502")//是否包含502
// if (e.getMessage().contains("502")||e.getMessage().contains("501")) {
// model.addAttribute("errMsg","非常抱歉:"+e.getMessage());
// return "/power/500";
// }
// return "/power/404";
// }
}
控制层
@RequestMapping("/checkEx")
public void checkEx() throws Exception {
if (!StpUtil.isLogin()) {
throw new Exception("502,您还没登录");
}
boolean role = StpUtil.hasRole("66");
if (!role) {
throw new Exception("501,此用户没有这个角色");
}
}
页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>404</title>
</head>
<body>
<h1 style="color: #8A2BE2">404,请停步,您没有这个角色权限!!!</h1>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>500</title>
</head>
<body>
<h1 style="color: #00ff00">${errMsg}</h1>
</body>
</html>
json格式处理
跳转页面格式
接口文档框架Swagger
导入swagger的依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
配置文件
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
配置类
package com.jwt.config;
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 //这个声明此类是接口文档配置类
@EnableSwaggerBootstrapUI //开启BootstrapUI
public class SwaggerConfig {
@Bean
public Docket initSwagger() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(this.builderApi())
.select() //选择器,选哪些类要生成接口文档
.apis(RequestHandlerSelectors.basePackage("com.jwt"))//用于指定扫描哪些包下的接口,any是扫描任何
.paths(PathSelectors.any())//选择所有的API,如果你想只为部分API生成文档,可以配置这里
.build();
return docket;
}
//初始化API设置
public ApiInfo builderApi() {
//设置模式是建造者模式,可以链式调用
ApiInfo api = new ApiInfoBuilder()
.description("接口文档描述信息")//描述
.title("Sa-token的接口文档")//标题
.version("v1.0")//版本
.contact(new Contact("milo","https://www.baidu.com","cxyali826@qq.com"))//联系人
.build();
return api;
}
}
ApiInfo对象里面的东西
访问路径
http://localhost:8086/swagger-ui.html
测试
package com.jwt.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jwt.service.UserService;
import com.jwt.vo.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/power")
@Api(value = "SaToken的鉴权接口", tags = "PowerController的鉴权接口")
public class PowerController {
@Autowired
UserService userService;
@ApiOperation("SaToken登录接口")//生成方法描述
@ApiImplicitParams({
@ApiImplicitParam(name = "username", value = "用户名"),//描述具体参数作用
@ApiImplicitParam(name = "password", value = "密码")
})//生成参数描述
@RequestMapping("/login")
public Object login(@RequestParam("username") String username,
@RequestParam("password") String password) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("uname", username)
.eq("upwd", password);
User user = userService.getOne(queryWrapper);
if (user != null) {
StpUtil.login(user.getUid());
return new SaResult(200, "", user);
}
return SaResult.error("登录失败,用户未登录");
}
}
导入BootStrapUI依赖
**访问路径:**http://localhost:8080/doc.html
@EnableSwaggerBootstrapUI //开启BootstrapUI
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.8.7</version>
</dependency>
SpringBoot过滤器,拦截器和监听器
过滤器
拦截器与过滤器的区别
- 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
- 拦截器内容不同:Filter对所有访问进行增强(在Tomcat服务器进行配置),Interceptor仅针对SpringMVC的访问进行增强
定义一个过滤器
package com.jwt.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
//@Component
@WebFilter(filterName = "tokenFilter",urlPatterns = "/*")
public class TokenFilter implements Filter {
Logger logger = LoggerFactory.getLogger(TokenFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("------------>调用init方法");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
logger.info("------------>调用doFilter方法");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
logger.info("------------>调用destroy方法");
}
}
注册过滤器
在启动类上加这个注解完成注册;
//加这个注解后,Servlet,Filter,Listener可以直接通过@WebServlet,@WebFilter,@WebListener注解自动注册
@ServletComponentScan
拦截器
作用:
- 在指定的方法调用前后执行预先设定的代码(比如权限的校验就是在访问controller之前校验)
- 阻止原始方法的执行(把原始的方法终止掉)
定义一个拦截器
package com.jwt.interceptor;
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;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取进过拦截器的路径
String requestURI = request.getRequestURI();
// 登录检查逻辑
HttpSession session = request.getSession();
Object token = session.getAttribute("token");
if (token != null) {
// 放行
return true;//true 本次拦截,false 不拦截
}
// 拦截 就是未登录,自动跳转到登录页面,然后写拦截住的逻辑
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
注册拦截器
package com.jwt.config;
import com.jwt.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class LoginWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 下面这句代码相当于添加一个拦截器 添加的拦截器就是我们刚刚创建的
registry.addInterceptor(new LoginInterceptor())
// addPathPatterns()配置我们要拦截哪些路径 addPathPatterns("/**")表示拦截所有请求,包括我们的静态资源
.addPathPatterns()
// excludePathPatterns()表示我们要放行哪些(表示不用经过拦截器)
// excludePathPatterns("/","/login")表示放行“/”与“/login”请求
// 如果有静态资源的时候可以在这个地方放行
.excludePathPatterns("/","/login");
// 第二个拦截器
// registry.addInterceptor(new LoginInterceptor2()).addPathPatterns("/books");
}
}
解决跨域问题
- 在后端重定向解决
- 失败返回一个状态码,然后在前端判断状态码,然后在前端实现跳转
监听器
SpringBoot邮件服务
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
配置
spring:
mail:
host: smtp.qq.com
username: 1693311433@qq.com
password: xxxx
properties:
mail:
smtp:
ssl:
enable: true
fromMail: 169xxxxxx@qq.com
发送方法
package com.jwt.service.impl;
import cn.hutool.core.util.RandomUtil;
import com.jwt.service.EmailService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
@Service
public class EmailServiceImpl implements EmailService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
JavaMailSender sender;
@Value("${fromMail}")
private String fromMail;
@Override
public void send(String qq) {
SimpleMailMessage message = new SimpleMailMessage();
message.setSubject("验证码");
// System.out.println(fromMail);
message.setText(String.valueOf(RandomUtil.randomInt(1000, 9999)));
message.setTo(qq);
message.setFrom(fromMail);
sender.send(message);
logger.info("邮件已发送!");
}
}
SpringBoot定时器
定义一个定时器类
package com.jwt.quartz;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
@EnableScheduling//开启定时功能
public class QuartzTest {
Logger logger = LoggerFactory.getLogger(QuartzTest.class);
//cron表达式在网上看
@Scheduled(cron = "*/5 * * * * *")//每秒执行一次
public void test() {
logger.info("-------------->定时任务");
}
}
SpringBoot+JPA
引入依赖和配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
url: jdbc:mysql://localhost:3306/springboot
password: 123456
jpa:
show-sql: true
实体类
package com.example.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
@Data
@Entity
@Table(name = "user")
public class AyUser {
@Id
private String id;
private String username;
private String password;
}
DAO层
要继承JpaRepository类
package com.example.dao;
import com.example.entity.AyUser;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AyUserRepository extends JpaRepository<AyUser,String> {
}
Serivice层
package com.example.service;
import com.example.entity.AyUser;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface AyUserService {
AyUser findById(String id);
List<AyUser>findAll();
AyUser save(AyUser ayUser);
void delete(String id);
//分页
Page<AyUser>findAll(Pageable pageable);
}
package com.example.service.impl;
import com.example.dao.AyUserRepository;
import com.example.entity.AyUser;
import com.example.service.AyUserService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class AyUserServiceImpl implements AyUserService {
@Resource(name = "ayUserRepository")
private AyUserRepository ayUserRepository;
@Override
public AyUser findById(String id) {
return ayUserRepository.findById(id).get();
}
@Override
public List<AyUser> findAll() {
return ayUserRepository.findAll();
}
@Override
public AyUser save(AyUser ayUser) {
return ayUserRepository.save(ayUser);
}
@Override
public void delete(String id) {
ayUserRepository.deleteById(id);
}
@Override
public Page<AyUser> findAll(Pageable pageable) {
return ayUserRepository.findAll(pageable);
}
}
自定义查询方法
测试
@SpringBootTest
class Springboot03ApplicationTests {
@Resource
AyUserService ayUserService;
@Test
void test01() {
List<AyUser> users = ayUserService.findAll();
System.out.println(users);
PageRequest pageable = PageRequest.of(0, 1);
Page<AyUser> all = ayUserService.findAll(pageable);
all.get().forEach(System.out::println);
}
}
SpringBoot事务的简单实现
//@Transactional 也可以加在在类上,这意味着该类或者public方法开启事务
@Transactional
@Override
public AyUser save(AyUser ayUser) {
AyUser user = ayUserRepository.save(ayUser);
String error = null;
//出现空指针
error.split("/");
return user;
}
测试
@Test
void test02() {
AyUser ayUser = new AyUser();
ayUser.setId("4");
ayUser.setUsername("ayUser");
ayUser.setPassword("123");
ayUserService.save(ayUser);
}
AyUser save(AyUser ayUser) {
return ayUserRepository.save(ayUser);
}
@Override
public void delete(String id) {
ayUserRepository.deleteById(id);
}
@Override
public Page<AyUser> findAll(Pageable pageable) {
return ayUserRepository.findAll(pageable);
}
}
自定义查询方法
[外链图片转存中…(img-eZMXKE6P-1706420611915)]
测试
@SpringBootTest
class Springboot03ApplicationTests {
@Resource
AyUserService ayUserService;
@Test
void test01() {
List<AyUser> users = ayUserService.findAll();
System.out.println(users);
PageRequest pageable = PageRequest.of(0, 1);
Page<AyUser> all = ayUserService.findAll(pageable);
all.get().forEach(System.out::println);
}
}
SpringBoot事务的简单实现
//@Transactional 也可以加在在类上,这意味着该类或者public方法开启事务
@Transactional
@Override
public AyUser save(AyUser ayUser) {
AyUser user = ayUserRepository.save(ayUser);
String error = null;
//出现空指针
error.split("/");
return user;
}
测试
@Test
void test02() {
AyUser ayUser = new AyUser();
ayUser.setId("4");
ayUser.setUsername("ayUser");
ayUser.setPassword("123");
ayUserService.save(ayUser);
}