文章目录
第二章 springboot
一、登录校验
1、会话技术
2、JWT令牌
1、定义:JWT(JSON Web Token),一种简洁的、自包含的格式,用于在通信双方以Json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。
2、组成
(1) 第一部分:Header(头),记录令牌类型、签名算法等。例如:{“alg”:“HS256”,“type”:“WT”}
(2) 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。例如:“id".“1”,“username”:"Tom”
(3) 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。
3、代码
public class JwtUtils {
private static String signKey = "itheima";
private static Long expire = 43200000L;
/**
* 生成JWT令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @return
*/
public static String generateJwt(Map<String, Object> claims){
String jwt = Jwts.builder()
.addClaims(claims) //自定义内容
.signWith(SignatureAlgorithm.HS256, signKey) //签名算法
.setExpiration(new Date(System.currentTimeMillis()+ expire)) //时间
.compact();
return jwt;
}
/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载 payload 中存储的内容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
2、过滤器Filter
1、定义:Filter是Javaweb的三大组件(Servlet、Filter、Listener)之一。Filter可以把对资源的请求拦截下来,从而实现一些特殊的功能。
2、拦截路径:
/login
/depts/*
/*
3、过滤器链:一个web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链。过滤器链优先级是按照过滤器类名(字符串)的自然排序。
4、登录校验Filter
(1) 定义Filter:定义一个Filter类,实现Filter接口并重写方法
(2) 配置Filter:Filter类上加@WebFilter注解,配置拦截资源的路径。引导类上加@ServletComponentScan 开启Servlet组件支持
<!-- Filter类 -->
@Slf4j
@WebFilter(urlPatterns = "/*") //拦截资源的路径
public class LoginCheckFilter implements Filter {
@Override//初始化方法,只调用一次
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化方法执行");
}
@Override//拦截请求之后调用,调用多次
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//1、获取请求url
String url = request.getRequestURI().toString();
log.info("请求的url:{}",url);
//2、判断请求url是否包含登录操作
if (url.contains("login")){
filterChain.doFilter(servletRequest,servletResponse);
return;
}
//3、获取请求头的令牌token
String jwt = request.getHeader("token");
//4、判断令牌是否存在
if(!StringUtils.hasLength(jwt)){
log.info("请求头token为空,返回未登录的信息");
Result error = Result.error("NOT_LOGIN");
//手动转换对象为json格式
String notLogin = JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return;
}
//5、解析token,如果解析失败,放回错误结果
try {
JwtUtils.parseJWT(jwt);
}catch (Exception e){
e.printStackTrace();
log.info("解析失败");
Result error = Result.error("NOT_LOGIN");
//手动转换对象为json格式
String notLogin = JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return;
}
//6、放行
log.info("令牌合法,放行");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override//销毁方法,只调用一次
public void destroy() {System.out.println("销毁方法执行");
}
<!-- 运行类 -->
@ServletComponentScan //开启了对servlet组件的支持
@SpringBootApplication
public class MybatisApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisApplication.class, args);
}
}
3、拦截器Interceptor
(1) 定义:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。
(2) 作用:拦截请求,在指定的方法调用前,根据业务需要执行预先设定的代码。
(3) 拦截路径
(4) 执行流程
(5) Filter和Interceptor的区别
a 接口规范不同: 过滤器需要实现Filter接口,而拦截器需要实现Handlerlnterceptor接口。
b 拦截范围不同: 过滤器Filter会拦截所有的资源,而interceptor只会拦截Spring环境中的资源(interceptor在Spring环境中)。
(6) 登录校验Interceptor
<!-- interceptor.LoginCheckInterceptor -->
@Slf4j
@Component //交给IOC容器管理
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override//目标资源方法运行前运行,返回true: 放行,放回false,不放行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandel...");
//1、获取请求url
String url = request.getRequestURI().toString();
log.info("请求的url:{}",url);
//2、判断请求url是否包含登录操作
if (url.contains("login")){
return true;
}
//3、获取请求头的令牌token
String jwt = request.getHeader("token");
//4、判断令牌是否存在
if(!StringUtils.hasLength(jwt)){
log.info("请求头token为空,返回未登录的信息");
Result error = Result.error("NOT_LOGIN");
//手动转换对象为json格式
String notLogin = JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return false;
}
//5、解析token,如果解析失败,放回错误结果
try {
JwtUtils.parseJWT(jwt);
}catch (Exception e){
e.printStackTrace();
log.info("解析失败");
Result error = Result.error("NOT_LOGIN");
//手动转换对象为json格式
String notLogin = JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return false;
}
//6、放行
log.info("令牌合法,放行");
return true;
}
@Override//目标资源方法运行后运行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandel...");
}
@Override//视图渲染完毕后运行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
<!-- config.Webconfig用于添加LoginCheckInterceptor拦截器 -->
@Configuration //配置类
public class Webconfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//addPathPatterns("/**")需要拦截哪些资源 excludePathPatterns("/login")不需要拦截哪些资源
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
}
}
二、异常捕获
1、定义全局异常处理器来处理异常
2、代码
<!-- exception.GlobalExceptionHandler -->
@RestControllerAdvice //开启全局异常捕获
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class) //捕获所有异常
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error("对不起,操作失败,请联系管理员");
}
}
三、配置文件
1、application.properties
server.port=8080
server.address=127.0.0.1
2、application.yml/application.yaml
server:
port:8080
address:127.0.0.1
3、application.yaml
server:
port:8080
address:127.0.0.1
第三章 spring
一、事务管理
1、定义:事务是一组操作的集合,它是一个不可分割的工作单位。事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
2、四大特性
3、事务控制
-- 开启事务(一组操作开始前开启事务)
start transaction; / begin ;
-- 提交事务(这组操作成功前提交事务)
commit;
-- 回滚事务(中间任何一个操作出现异常,回滚事务)
rollback;
4、@注解
(1) 注解:@Transactional,代表方法具有事务
(2) 属性
a、rollbackFor:默认情况下,只有出现 RuntimeException 才回滚异常。rollbackFor属性用于控制出现何种异常类型,回滚事务
b、propagation:事务传播行为,当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。
@Transactional(rollbackFor = Exception.class) //指定所有异常都会进行事务回滚
//:当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功。
@Transactional(propagation = Propagation.REQUIRED_NEW)
(2) 位置:业务(service)层的方法上、类上、接口上
(3) 作用:将当前方法交给spring进行事务管理,方法执行前,开启事务,成功执行完毕,提交事务,出现异常,回滚事务。
二、三大核心思想
2.1 控制反转IOC
1、定义:Inversion Of Control控制反转,简称IOC。对象的创建控制权由程序自身转移到外部(容器)
2、bean对象:IOC容器中创建、管理的对象,称之为bean.
3、将对象交给IOC容器管理,需要在对应的类上加上对应的注解
4、获取bean:默认情况下,Spring项目启动时,会把bean都创建好放在10C容器中,可以通过如下方式来主动获取bean对象。
(1) 根据名字获取bean:Object getBean(String name)
(2) 根据类型获取bean:< T > T getBean(Class< T > requiredType)
(3) 根据name获取bean:< T > T getBean(String name,Class< T > requiredType)
@SpringBootTest
class MybatisApplicationTests {
@Autowired
private ApplicationContext applicationContext; //IOC容器对象
@Test
void GettestBean(){
//根据bean的名称获取
DeptController bean1=(DeptController) applicationContext.getBean("deptController");
System.out.println(bean1); //com.itheima.controller.DeptController@4a122e68
//根据bean的类型获取
DeptController bean2=applicationContext.getBean(DeptController.class);
System.out.println(bean2); //com.itheima.controller.DeptController@4a122e68
//根据bean的类型获取
DeptController bean3=applicationContext.getBean("deptController",DeptController.class);
System.out.println(bean3); //com.itheima.controller.DeptController@4a122e68
}
3、bean的作用域:通过@Scope注解来配置作用域
@Scope(prototype) //设置bean的作用域
@RestController
@RequestMapping("/depts")
public class DeptController{}
4、第三方bean:如果要管理的bean对象来自于第三方(不是自定义的),是无法用@omponent 及衍生注解声明bean的,就需要用到 @Bean注解。若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过 @Configuration 注解声明一个配置类。
//通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名
@Configuration //配置类
public class CommonConfig {
//声明第三方bean
@Bean //将当前方法的返网值对象交分IOC容器管理,成为IOC容器bean
public SAXReader saxReader(){
return new SAXReader();
}
//如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配
//public SAXReader saxReader(DeptController deptController){}
}
2.2 依赖注入DI
1、定义:Dependency Injection依赖注入,简称DI。容器为应用程序提供运行时所依赖的资源。
2、使用方法:使用@Autowired进行依赖注入,默认按照类型进行
3、若同类型的bean存在多个,则使用其他注解来判断优先级
(1) @Primary
@Primary //在bean前加上@Primary
@Service
public class EmpServiceA implements EmpService{}
(2) @Qualifier
@RestController
public class EmpController{
@Autowired //@Autowired +@Qualifier("bean的名称”)
@Qualifier("empServiceA")
private EmpService empService;
}
(3) Resource
@RestController //@Resource(name="bean的名称”)
public class EmpController{
@Resource("empServiceA")
private EmpService empService;
}
2.3 面向切面编程AOP
1、定义:Aspect Oriented Programming (面向切面编程、面向方面编程)其实就是面向特定方法编程。
2、通知
(1) 通知类型
a、@Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
b、@Before:前置通知,此注解标注的通知方法在目标方法前被执行
c、@After:后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
d、@AfterReturning:返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
e、@AfterThrowing :异常后通知,此注解标注的通知方法发生异常后执行
f、@PointCut:将公共的切点表达式抽取出来,需要用到时引用该切点表达式即可
(2) 通知顺序:当有多个切面的切入点都匹配到了目标方法,目标方法运行时,多个通知方法都会被执行。
a、不同切面类中,默认按照切面类的类名字母排序
目标方法前的通知方法:字母排名靠前的先执行
目标方法后的通知方法:字母排名靠前的后执行
b、用 @Order(数字)加在切面类上来控制顺序
目标方法前的通知方法:数字小的先执行
目标方法后的通知方法:数字小的后执行
3、切入点表达式
(1) 作用:主要用来决定项目中的哪些方法需要加入通知
(2) 切入点表达式——execution:主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配。 其中“ * ”代表单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分。"…"代表多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
//其中带?的表示可以省略的部分
execution(访问修饰符? 返回值 包名.类名.? 方法名(方法参数) throws 异常?)
execution(public void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))
execution(* com.itheima..DeptServiceImpl.*(..))
@PointCut("execution(* com.itheima.service.*.*(..))")
public void pt(){}
@Around("pt()")
public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
}
(3) 切入点表达式——@annotation:用于匹配标识有特定注解的方法。
<!-- 设定一个特定注解annotation:MyLog -->
//使用两个原注解来描述当前注解
@Retention(RetentionPolicy.RUNTIME) //指定运行时生效
@Target(ElementType.METHOD) //指定当前注解的作用范围,METHOD指定在方法上生效
public @interface MyLog {
}
<!-- 在方法上标明特定注解MyLog -->
@MyLog
@Override
public void detete(Integer id) {
deptMapper.delete(id);
}
@Slf4j
@Aspect
@Component
public class MysAspect01 {
@Pointcut("@annotation(com.itheima.aop.MyLog)")
private void pt(){
}
@Before("pt()")
public void before(){
log.info("before...");
}
}
4、连接点
(1) 定义:在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。
(2) 连接点的使用
① 对于@Around 通知,获取连接点信息只能使用 ProceedingJoinPoint
② 对于其他四种通知,获取连接点信息只能使用 JoinPoint ,它是 ProceedingJoinPoint的父类型
@Before("execution(* com.itheima.service.*.*(..))")
public void before(){
String classname = joinPoint.getTarget().getClass().getName(); //获取目标类名
String signature = joinPoint.getSignature().getName(); //获取目标方法名
Object[] args = joinPoint.getArgs(); //获取目标方法运行参数
}