一、Restful
package com.example.crudtest1.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {private Integer code;//响应码,1 代表成功; 0 代表失败private String msg; //响应信息 描述字符串private Object data; //返回的数据//增删改 成功响应public static Result success(){return new Result(1,"success",null);}//查询 成功响应public static Result success(Object data){return new Result(1,"success",data);}//失败响应public static Result error(String msg){return new Result(0,msg,null);}
}
二、日志输出
项目开发中尽量避免使用sout输出,使用日志输出
private static Logger log = LoggerFactory.getLogger(DeptController.class);//或者使用注解
@Slf4j
三、分页查询
注意sql中limit的第一个参数即可
例如查询第二页,每页展示10条数据
selcet * from emp limit 10,10
3.1、分页查询插件PageHelper
四、文件上传
4.1、前端
前端,必须提供form表单,提交方式为post 必须要有个input框设置为file
enctype 属性值 如果需要文件上传,必须使用multipart/form-data
4.2、后端
后端在spring boot中使用 MultpartFile 且表单项名字前后端一致
4.3、本地存储
前置知识
1、
这是pom.xml配置文件:
Spring Boot 默认的文件上传大小限制是 1MB。如果上传文件过大,可以自行配置:
#配置单个文件最大上传大小
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大大小的限制(一次请求中是可以上传多个文件)
spring.servlet.multipart.max-request-size=10MB
2、由于上传的图片可能会出现同名问题,我们需要给一个唯一的标识,这里推荐使用UUID
,拼接原始的上传文件名
Controller层
/** 文件上传* */@PostMapping("/upload")public Result upload(String username, Integer age, MultipartFile image) throws Exception {log.info("文件上传,{},{},{}",username,age,image);//获取原始文件名String originalFilename = image.getOriginalFilename();//构造唯一的文件名(不能重复)--uuid(通用唯一识别码) a758f47d-8807-4d50-af22-5b4b3208f193int index = originalFilename.lastIndexOf(".");String extname = originalFilename.substring(index);String newFileName = UUID.randomUUID().toString()+extname;log.info("新的文件名:{}", newFileName);//将文件存储在服务器磁盘下image.transferTo(new File("G:\\笔记\\Java\\project\\" +"springboot-mybatis-crudTest\\crudTest1\\image\\"+newFileName));return Result.success();}
4.4、阿里云OSS存储
流程
- 登录阿里云->控制台->oss基础服务
- 点击Bucket列表->创建bucket->输入名称,创建
- 获取密钥,点击头像AccessKey管理-创建一个账号
- 回到oss服务,拉到最下面找到SDK下载,就可以看到官方文档
https://help.aliyun.com/zh/oss/developer-reference/overview-21
引入依赖
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.15.1</version>
</dependency>//java9以上<dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version>
</dependency>
<dependency><groupId>javax.activation</groupId><artifactId>activation</artifactId><version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency><groupId>org.glassfish.jaxb</groupId><artifactId>jaxb-runtime</artifactId><version>2.3.3</version>
</dependency>
引入工具类
package com.example.crudtest1.utils;import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.UUID;/*** 阿里云 OSS 工具类*/
public class AliOSSUtils {private String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";private String accessKeyId = "LTAI4GCH1vX6DKqJWxd6nEuW";private String accessKeySecret = "yBshYweHOpqDuhCArrVHwIiBKpyqSL";private String bucketName = "web-tlias";/*** 实现上传图片到OSS*/public String upload(MultipartFile file) throws IOException {// 获取上传的文件的输入流InputStream inputStream = file.getInputStream();// 避免文件覆盖String originalFilename = file.getOriginalFilename();String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));//上传文件到 OSSOSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);ossClient.putObject(bucketName, fileName, inputStream);//文件访问路径String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;// 关闭ossClientossClient.shutdown();return url;// 把上传到oss的路径返回}}
五、配置文件
优化阿里云配置文件,利用@ConfigurationProperties(prefix = “aliyun.oss”)
这里的属性必须要与yml配置文件里面同名
在AliOSSUtils中利用注解注入
package com.example.crudtest1.utils;import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.UUID;/*** 阿里云 OSS 工具类*/@Componentpublic class AliOSSUtils {@Autowired
private AliOSSProperties aliOSSProperties;/*** 实现上传图片到OSS*/public String upload(MultipartFile file) throws IOException {String endpoint = aliOSSProperties.getEndpoint();String accessKeyId = aliOSSProperties.getAccessKeyId();String accessKeySecret = aliOSSProperties.getAccessKeySecret();String bucketName = aliOSSProperties.getBucketName();// 获取上传的文件的输入流InputStream inputStream = file.getInputStream();// 避免文件覆盖String originalFilename = file.getOriginalFilename();String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));//上传文件到 OSSOSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);ossClient.putObject(bucketName, fileName, inputStream);//文件访问路径String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;// 关闭ossClientossClient.shutdown();return url;// 把上传到oss的路径返回}}
5.1、yml配置文件
基本语法
- 大小写敏感
- 数值前边必须有空格,作为分隔符
- 使用缩进表示层级关系,缩进时,不允许使用Tab键,只能用空格(idea中会自动将Tab转换为空格)
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
- #表示注释,从这个字符一直到行尾,都会被解析器忽略
server:port: 9000#定义对象/map集合
user:name:Tomage:18#定义Liset/set集合
hobby:-java-java2spring:#数据库连接datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/tliasusername:password:#文件上传servlet:multipart:max-file-size: 10MBmax-request-size: 100MB#mybatis
mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true#阿里云OSS
aliyun:oss:endpoint : "";accessKeyId : "";accessKeySecret : "";bucketName : "";
六、登录校验
会话技术
会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。
会话跟踪
一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。
6.1、JWT令牌
由三个部分组成,由Base64进行编码
- header(头)
- Payload(有效载荷)
- Signature(签名)
在登录成功后,生成令牌,后续每个请求都需要携带令牌,系统在处理请求时,需要先校验令牌
6.1.1、依赖
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>
工具类
package com.example.crudtest1.utils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;public class JwtUtils {private static String signKey = "zyyy";//设置生成时间为12小时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;}
}
七、过滤与拦截
过滤器链,由多个过滤器组成,由类文件名A-Z执行
7.2、拦截器
定义拦截器,实现HandlerInterceptor接口,并重写其所有方法
package com.example.crudtest1.interceptor;import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Override //目标资源方法前运行, 返回true 放行,返回false 不放行public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("目标资源方法前运行");
// return HandlerInterceptor.super.preHandle(request, response, handler);return true;}@Override //目标资源方法后运行public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);System.out.println("目标资源方法后运行");}@Override //视图渲染完后执行public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// HandlerInterceptor.super.afterCompletion(request, response, handler, ex);System.out.println("视图渲染完后执行");}
}
注册拦截器
package com.example.crudtest1.config;import com.example.crudtest1.interceptor.LoginCheckInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
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 WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//要拦截哪些资源 addPathPatterns
//excludePathPatterns 放行registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");;}
}
执行流程
八、异常处理
全局异常处理器 RestControllerAdvice
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)//捕获全部异常public Result ex(Exception e){e.printStackTrace();return Result.error("操作失败,请联系管理员");}
}
九、事务管理
事务:一组操作集合,不可分割,要么同时成功,要么失败
注解@Transactional
注意 默认情况下只会出现RuntimeException才回滚异常
可以设置rollbackFor 来指定出现何种异常回滚
#spring事务管理日志
logging:level:org.springframework.jdbc.support.JdbcTransactionManager: debug
9.1、传播行为
事务传播行为:指的是一个事务方法被另一个事务调用
10、AOP
AOP:面向切面编程,就是面向特定的方法编程
通过底层的动态代理机制,对特定的方法进行编程
- 引入依赖
<dependency><groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId></dependency>
获取每个方法的运行时长
package com.example.crudtest1.aop;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;@Slf4j
@Component
@Aspect
public class TimeAspect {@Around("execution(* com.example.crudtest1.service..*.*(..))")public Object recordTime(ProceedingJoinPoint joinPoint ) throws Throwable {//1.记录开始时间long begin = System.currentTimeMillis();//调用原始方法运行Object result = joinPoint.proceed();//记录结束时间,计算方法执行耗时long end = System.currentTimeMillis();log.info(joinPoint.getSignature()+ "方法耗时,{}",end-begin);return result;}
}
10.1、核心概念
- 连接点:JoinPoint,可以被AOP控制的方法
- 通知:Advice,指重复的逻辑,也就是共性功能
- 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
这里表现的是只有list这一个功能点运行时,才会被通知
- 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
- 目标对象:Target,通知所应用的对象
执行流程
10.2、通知类 
@Pointcut 切入点,可以将重复的片段抽取起来统一使用
@Pointcut("execution(* com.example.crudtest1.service.impl.DeptServiceImpl.*(..))")public void pt(){};@Before("pt()")public void before(){log.info("before ...");}
不同切面类中,默认按照切面类的类名字母排序:
目标方法前的通知方法:字母排名靠前的先执行
目标方法后的通知方法:字母排名靠前的后执行
可以使用@Order(数字)控制顺序
目标方法前的通知方法:数字越小前的先执行
目标方法后的通知方法:数字越小的后执行
10.3、切入点表达式
- execution():根据方法的签名来进行匹配
书写建议
所有业务方法名在命名时尽量规范,方便切入点表达式快速匹配。如:查询类方法都是find开头,更新类方法都是update开头。
描述切入点方法通常基于接口描述,而不是直接描述实现类,增强拓展性。
在满足业务需要的前提下,尽量缩小切入点的匹配范围。如:包名匹配尽量不使用…使用*匹配单个包。
- @annotation():根据注解匹配
10.4、连接点
JoinPoint抽象了连接点,可以用它获得方法执行时的相关信息,如目标类、方法名、方法参数
注意点:
@Around通知,获取连接点信息只能使用ProceedingJoinPoint
其他四种通知,获取连接点信息只能使用JoinPoint
它是ProceedingJoinPoint的父类型
//1、获取目标对象的类名String className = proceedingJoinPoint.getClass().getName();log.info("目标对象的类名,{}",className);//2.获取目标方法的方法名String methodName = proceedingJoinPoint.getSignature().getName();log.info("目标对象的类名,{}",methodName);//3.获取目标运行时传入的参数Object[] args = proceedingJoinPoint.getArgs();log.info("目标对象的类名,{}", Arrays.toString(args));//4.放行 目标方法执行Object result = proceedingJoinPoint.proceed();
11.springBoot原理
配置优先级问题
第三方Bean对象
- 如果要管理的bean对象来自于第三方(不是自定义的),是无法用@Component及衍生注解声明bean的,就需要用到@Bean注解。
- 若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过@Configuration注解声明一个配置类。
11.1、起步依赖
spring boot 中引入项目依赖不需要那么繁琐,主要靠依赖传递,保证引入项目需要的依赖
11.2、自动配置
SpringBoot的自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。
-
原理实现
- @import
- @EnableXXX注解,封装了@Import(推荐)
-
源码
-
@SpringBootApplication
-
@SpringBootConfiguration
- 和configuration注解作用相同,声明当前也是一个配置类
-
@EnableAutoConfiguration
- 组件扫描,默认扫描当前引导类所在包及其子类
-
@ComponentScan
- 实现自动化配置的核心注解
-
-
条件装配注解
- Conditional注解
- 按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到Spring IOC容器中
- 常用Conditional注解
- @ConditionalOnClass:判断是否有对应的字节码文件
- @ConditionalOnMissingBean:判断环境中没有对应的bean才会注入
- @ConditionalOnProperty:判断配置文件中对应属性和值,才注册bean到IOC容器
11.3、案例(自动starter)
自定义起步依赖-制作阿里云工具类的自动装配
12、maven
12.1、继承与聚合
作用
聚合用于快速构建项目
继承用于简化依赖配置、统一管理依赖
相同点:
聚合与继承的pom.xml文件打包方式均为pom,可以将两种关系制作到同一个pom文件中聚合与继承均属于设计型模块,并无实际的模块内容
不同点:
聚合是在聚合工程中配置关系,聚合可以感知到参与聚合的模块有哪些继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己
12.2、私服
私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,用来代理位于外部的中央仓库,用于解决团队内部的资源共享与资源同步问题。
- Release:发行版本,功能趋于稳定,当前停止更新
- snapshot:快照版本,功能不稳定、尚且 处于开发中的版本
步骤
- 配置本地仓库访问私服的权限,修改maven的conf/settings.xml配置文件,指定访问私服的用户名/密码
<server><id>releases</id><username>admin</username>#这里是私服设置的密码<password>123456</password>
</server>
<server><id>snapshots</id><username>admin</username>#这里是私服设置的密码<password>123456</password>
</server>
- IDEA中配置要上传项目中的发布管理,修改pom.xml,指定上传的位置
<distributionManagement><repository><id>releases</id><url>http://localhost:8081/repository/maven-releases/</url></repository> <snapshotRepository><id>snapshots</id><url>http://localhost:8081/repository/maven-snapshots/</url></snapshotRepository>
</distributionManagement>