记录了一些在学习SpringBoot和MyBatis时的知识点
SpringBoot
简介
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring
Boot致力于在蓬勃发展的快速应用开发成为领导者。
依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 3.2.4</version > </parent > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-validation</artifactId > </dependency > </dependencies > </project >
启动类
springboot通过创建启动类和main函数调用对应的方法启动项目,启动类需要放在软件包的根目录
1 2 3 4 5 6 7 8 9 10 11 package com.forum;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class Start { public static void main (String[] args) { SpringApplication.run(Start.class, args); } }
分层解耦思想
controller:控制层
控制层只负责接受请求和返回参数,所有业务逻辑在service层实现,controller通过调用services层方法来实现业务处理。
Service:业务逻辑层
业务逻辑层负责业务的实现,通过调取dao层实现对数据库进行操作并为controller层提供业务处理方法。
Dao:数据访问层
数据访问层负责对数据库进行增删改查等操作,为业务逻辑层处理数据提供操作数据库的方法。
IOC和DI
通常情况下控制层需要创建业务逻辑层对象调用方法来实现业务处理,业务逻辑层通过创建数据访问层对象调用方法来实现数据访问,这种方式增加了各个层之间的依赖程度,当一个层中的方法出现改变,那么另一个层中的调用也需要进行相应修改。spring为了解决这个问题提出了IOC的概念。
IOC是一个容器,他通过注解的形式将对应的类对象放入容器中统一管理,其他层使用时只需要声明即可取出对象而不需要再创建对象
@RestController
创建控制层对象交给IOC(控制层类必须有该注解)
@Service
创建业务逻辑层数据对象交给IOC
@Mapper
创建数据控制层对象交给IOC(需要Mybatis)
@@Autowired
从IOC容器中取出该类型对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class UserCotroller { @Autowired private UserServiceImpl userServiceImpl; @PostMapping("adduser") public Result addUser () { pass } } @Service public class UserServiceImpl implements Userservice { @Autowired private UserMapper userMapper; @Transactional public boolean addUser (User user) { pass } } @Mapper public interface UserMapper { public void addUser (User user) ; }
Controller层
@RequestMapping (“user”)
设置路由,可以在作用在类、方法上
@GetMapping (“#{id}”)
设置路由,只接受GET请求(POST,DELECT,PULL请求同上)
@RequestBody
作用在参数上,可以接收POST请求参数
@PathVariable
作用在参数上,可以接收路由参数
@Validated
校验参数是否符合要求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @RestController @RequestMapping("user") public class UserCotroller { @PostMapping("adduser") public Result addUser (@RequestBody @Validated User user) {} @GetMapping("#{id}") public Result vistUser (@PathVariable int id) {} } @Data public class User { @Null private Integer uid; @NotBlank @Size(min = 2, max = 20) private String username; @NotBlank @Size(min = 2, max = 20) private String password; @NotBlank @Pattern(regexp="^[男,女]") private String sex; @NotNull private Integer role; private String head; private LocalDate createTime; private LocalDate endTime; }
事务管理
开启事物
通过在方法、类和接口上面添加@Transactional 注解来开启事物
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.forum.service;import com.forum.mapper.UserMapper;import com.forum.pojo.User;import com.forum.service.port.Userservice;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.time.LocalDate;@Service public class UserServiceImpl implements Userservice { @Autowired private UserMapper userMapper; @Transactional public boolean addUser (User user) { LocalDate localDate = LocalDate.now(); user.setCreateTime(localDate); user.setEndTime(localDate); if (user.getRole() == 0 ){ userMapper.addUser(user); return true ; }else { System.out.println("判断是否为管理员操作---------暂未实现" ); return false ; } } }
事务属性
rollbackFor
设置出现何种错误才回滚
propagation
当该事物方法被调用时事物的处理方式
Propagation.REQUIRED
有则加入调用方法的事务,没有创建方法
Propagation.REQUIRES_NEW
创建新事务
Propagation.SUPPORTS
有则加入,没有则无事物运行
Propagation.NOT_SUPPORTED
不支持事物,调用方法有事务时挂起当前事物
Propagation.MANDATORY
必须有事物,否则抛出异常
Propagation.NEVER
必须没事务,否则抛出异常
1 2 3 4 5 6 7 8 @Transactional public void a () { b() } @Transactional(Propagation.REQUIRES_NEW) public void a () { pass }
开启事务管理的debug日志
1 logging.level.org.springframework.jdbc.support.JdbcTransactionManager =debug
文件上传
1 2 3 4 5 6 7 <form action ="/upload" method ="post" enctype ="multipart/form-data" > <input type ="file" name ="file" /> </form >
1 2 3 4 5 6 7 public Result upload (MultipartFile file) { String fileName = file.getOriginalFilename(); file.transferTo(new File (fileName)); }
设置上传文件大小
1 2 3 4 spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-request-size=100MB
会话技术
加入依赖
1 2 3 4 5 <dependency > <groupId > io.jsonwebtoken</groupId > <artifactId > jjwt</artifactId > <version > 0.9.1</version > </dependency >
加密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public Result login () { Map<String,Object> map = new HashMap <>(); map.put("uid" ,user.getUid()); map.put("username" ,user.getUsername()); String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, "SVRIRULNQQ==" ) .addClaims(map) .setExpiration(new Date (System.currentTimeMillis() + 12 *1500 *1000 )) .compact(); return Result.SUCCESS("" ); } public static String generateJwt (User user) { String token = Jwts.builder() .claim("uid" , user.getUid()) .claim("username" , user.getUsername()) .claim("role" , user.getRole()) .expiration(new Date (System.currentTimeMillis() + TIME)) .signWith(KEY) .compact(); return token; }
解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public Result login () { Claims claims = Jwts.parser().setSigningKey("SVRIRULNQQ==" ) .parseClaimsJws("token" ) .getBody(); return Result.SUCCESS("" ); } public static Claims parseJwt (String token) { return Jwts.parser() .verifyWith(KEY) .build() .parseSignedClaims(token) .getPayload(); }
过滤器
定义Filter::定义一个类,实现Filter接口,重写方法
配置Filter:在Filter类上加@WebFilter注解,配置拦截路径,启动类上加@ServletComponentScan开启Servlet组件支持。
tip : filter过滤器放行后还会回到dofilter方法中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @WebFilter(value = "/*") public class DemoFilter implements Filter { @Override public void init (FilterConfig filterConfig) throws ServletException { Filter.super .init(filterConfig); } @Override public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy () { Filter.super .destroy(); } }
登陆验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @WebFilter(value = "/*") public class DemoFilter implements Filter { @Override public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; String uri = request.getRequestURI(); if (uri.equals("/login" )) { filterChain.doFilter(servletRequest, servletResponse); return ; } String token = request.getHeader("token" ); if (token == null ) { response.setStatus(401 ); return ; } filterChain.doFilter(servletRequest, servletResponse); } }
拦截器
定义一个拦截器类,实现HandlerInterceptor接口,重写方法
创建配置类,注册拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Component public class DemoInterceptor implements HandlerInterceptor { @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true ; } @Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { return ; } @Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { return ; } } @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private DemoInterceptor demoInterceptor; @Override public void addInterceptors (InterceptorRegistry registry) { registry.addInterceptor(demoInterceptor) .addPathPatterns("/**" ) .excludePathPatterns("/login" ); } }
/*
拦截一级路径(拦截/usr/不拦/usr/bin)
/**
任意级路径
/usr/*
拦截/usr下的一级路径
/usr/**
拦截/usr下的任意级路径
AOP
加入依赖
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-aop</artifactId > </dependency >
连接点:JoinPoint
可以被AOP控制的方法(可以被aop作用的方法)
通知:Advice
所抽出来的共性方法(AOP方法)
切入点:PointCut
AOP方法所作用的方法(@Around中匹配的方法 )
切面:Aspect
通知+注解
目标对象:Target
AOP函数所作用的对象
通知类型
@Around
环绕通知,通知方法在目标方法前后都执行
@Before
前置通知,通知方法在目标方法前被执行
@After
后置通知,通知方法在目标方法后被执行,无论异常都通知
@AfterReturning
返回后通知,通知方法在目标方法后被执行,有异常不会执行
@AfterThrowing
异常后通知,通知方法在发生异常后执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Aspect @Component public class AopTest { @Around("execution(* com.sky.controller.admin.*(*))") public Object around (ProceedingJoinPoint joinPoint) throws Throwable{ long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); long end = System.currentTimeMillis(); return result; } }
自定义通知执行顺序
在切面使用@Order注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Order(1) @Aspect @Component public class AopTest { @Around("execution(* com.sky.controller.admin.*(*))") public Object around (ProceedingJoinPoint joinPoint) throws Throwable{ long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); long end = System.currentTimeMillis(); return result; } }
使用annotation注解
创建自定义注解
在通知方法上使用@@Pointcut (“@annotation (自定义注解路径)”)
在连接点使用自定义注解注解方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyAop {} public class AopTest { @Pointcut("@annotation(com.sky.controller.admin.MyAop)") public Object around (ProceedingJoinPoint joinPoint) throws Throwable{ long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); long end = System.currentTimeMillis(); return result; } } @MyAop public Object around (ProceedingJoinPoint joinPoint) throws Throwable{ long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); long end = System.currentTimeMillis(); return result; }
连接点对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Before("execution(* com.sky.controller.admin.*(*))") public void around (ProceedingJoinPoint joinPoint) throws Throwable{ String name = joinPoint.getTarget().getClass().getName(); Signature signature = joinPoint.getSignature(); String methodName = signature.getName(); Object[] args = joinPoint.getArgs(); Object proceed = joinPoint.proceed(); }
Mybatis
简介
MyBatis 是一款优秀的持久层框架,它支持自定义
SQL、以及高级映射。MyBatis 免除了几乎所有的 JDBC
代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML
或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java
Objects,普通老式 Java 对象)为数据库中的记录。
Mybati提供注解开发和xml开发两种开发方式,相比于注解开发,xml开发支持动态sql更加灵活。
pom文件
配置
1 2 3 4 5 6 7 8 9 spring.datasource.url =jdbc:mysql://local/forum spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver spring.datasource.username =root spring.datasource.password =root mybatis.configuration.log-impl =org.apache.ibatis.logging.stdout.StdOutImpl mybatis.configuration.map-underscore-to-camel-case =true
注解开发
xml开发