深入学习spring-boot
深入学习springboot之无敌诀窍--查文档spring.io/projects/sp…
1.一天一个开发小技巧之---Lombok
第一步:引入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
第二步:idea中下载插件(切记搜索的时候要搜索Lombok plugin )
lombok使用:
@Data:
自动生成getter和setter方法(在编译的时候生成,代码中不体现)
@ToString
自动生成tostring方法
@AllArgsConstructor
全参构造器
@NoArgsConstructor
无参构造器
@EqualsAndHashCode
重写hashcode
@slf4j
里面带有一个log.info("内容");,可以打印信息,用于测试;
2.一天一个开发小技巧之---dev-tools
自动重启项目(热更新项目);本人觉得没什么用,所以不过多的描述了(我是菜鸡,只是我不会用罢了)。
还是过多的描述一下
首先,我们引入devtools这个依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
然后,我们需要配置一下
<build>
<finalName>Spring_cloud</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
再然后,我们使用ctrl + shift + alt + /进入 mainintenance 选择registery,然后勾选如下图
最后重启idea,即可生效
3.简单功能分析
3.1静态资源的访问
只要静态资源放在类路径下的:/static 或者/public 或者 /resources或者/META-INF/resources;那么只需要访问当前项目的根路径+静态资源名(即使静态资源路径改变,也是根路径加上【前缀】+静态资源名)。
原理:请求进来会先去controller查找处理,否则就会去静态资源路径下查找处理。
可以改变静态资源的类路径:
`resources:`
static-locations: classpath:/文件夹/
(可以更改多个,[路径1,路径2,,])
3.2静态资源访问前缀
spring:
mvc:
static-path-pattern: /res/**
当前项目+ static-path-pattern+ 静态资源名 =静态资源文件夹下的资源【会导致默认欢迎页面失效,也会影响favicon功能】
3.3、欢迎页的支持
3.3.1静态资源路径下放一个index.html
配置静态资源路径支持,但是如果配置了静态资源前缀就会导致不能被默认访问(底层仍然只有/**下的index.html但是由于静态资源路径路径有了前缀,所以访问不到了)。
3.3.2controller能处理/index
3.4、自定义favicon
将图标放在静态资源路径下,就会自动作为网站图标(仍然会受到静态资源前缀的影响)。
3.5静态资源配置原理
springboot启动时默认加载xxxAutoConfiguration类(springbootApplication中包含这个注解)
springMVC功能的自动配置类WebMvcConfiguration
4、请求参数的处理
4.1请求映射
@xxxMapping;
rest风格支持(使用http请求方式来表示对资源的操作)
对用户的操作统一使用/user路径,通过请求方法的不同来区分不同的操作 : GET--获取用户;DELETE--删除用户; PUT--修改用户; POST--保存用户;
实现的核心是Filter;HiddenHttpMethodFilter
用法:1.表单method = post,隐藏域_method=put;
2.springboot手动开启
spring:
mvc:
hiddenmethod:
filter:
enabled: true
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
rest原理(表单提交的时候):
表单提交需要带上_method=put/DELETE(通常是隐藏的hidden)
请求过去在底层被HiddenHttpMethodFilter拦截,
查看请求正常,是不是post
获取到_method的值(支持put,delete方式)
原生的request(post)请求,包装模式requestwrapper则重写了这个getMethod方法,返回的是传入的请求方法
过滤器链放行的时候用wrapper,以后的方法调用getMethod是调用requestwrapper的。
以上只支持表单提交。如果是客户端(postman)发送请求则可以直接发送put和delete请求。
所有请求映射都保存在了handlermapping中,然后从前到后的到handlermapping中去查找。最先查找的是requestmapping,然后是welcomemapping,之后还有三个handlermapping。
5、请求参数处理注解
@PathVariable:路径变量,通过路径上变量的不同,来获取不同的传递参数,从而获取到不同的信息。
@RequestHeader:获取请求头,获取到请求头里面的一些参数,支持获取全部的请求头,用map封装。
@ModelAttribute:
@RequestParam:获取参数。
@MaxtriVariable:矩阵变量(可以用来解决cookie失效的问题)
同时需要依赖路径变量(路径变量就是矩阵变量开始的地方),springboot默认是关闭矩阵变量的(默认将分号后面的内容扔掉)。两种方法开启(具体看代码)一、重写路径匹配方法configurePathMatch
二、写一个webmvcConfigutor组件添加到容器中,然后重写里面的configurePathMatch方法。
@CookieValue:获取cookie,当用string接受的时候获取的是cookie的值,当声明一个cookie接受的时候获取的就 cookie,然后调用方法获取cookie的名字和值。
@RequestBody:获取请求体
请求参数处理的原理
-
handlerMapping中找到处理请求的handler(controller.method())
-
位当前handler找到一个适配器 HandlerAdapter
0- 支持方法注解@RequestMapping
1- 支持函数式变成的
3.执行目标方法
4.参数解析器(确定每一个目标方法的每一个参数的值是什么)
当前解析器是否支持解析
5.返回值处理器
复杂参数
Map,Model里面的数据就是放在request的请求域中的
Map<String,Object> map,Model model,HttpServletRequest request都是给request中放数据
数据绑定:
自定义类型参数,使用的是ServletModelAttributeMethodProcessor这个参数处理器处理。(以后补学:自定义数据绑定方式)
数据响应
内容协商
根据客户端接收能力的不同,返回不同类型的数据
可以开启参数形式的返回数据格式
spring:
mvc:
contentnegotiation:
favor-parameter: true #开启请求参数内容协商模式
http://localhost:8888/saveuser?format=json
引入依赖
<!--支持xml数据返回格式-->
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
测试返回类型,只需修改请求头中的accept字段的值。告诉服务器,客户端能接收的数据格式
原理:
1、判断当前响应头中是否已经有了确定的媒体类型
2、获取客户端支持的内容类型。(Accept请求头【application/xml】)
3、便利循环当前所有的MessageConverter,看谁能支持操作这个对象。
4、找到支持操作返回类型的converter,吧converter支持的媒体类型统计出来
5、客户端需要哪种(application/xml)服务端的能力【10种,json,xml,等】
6、进行内容协商的最佳匹配媒体类型
视图解析与模板引擎
模板引擎--thymeleaf(现代化服务端的Java模板引擎,类似jsp,不适合高并发)
引入 依赖
<!--现代化服务端模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
自动配置好了themeleaf。
页面开发
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title >Title</title>
</head>
<body>
<h1 th:text="${msg}">你好</h1>
<h2>
<a href="http://www.baidu.com" th:href="${link}">去百度</a>
<a href="http://www.baidu.com" th:href="@{link}">去百度</a>
</h2>
</body>
</html>
@ {} 和$ {}的区别
前者是将取得的值拼接到路径或者其他数据后面,后者是将值赋值给其他属性。
拦截器原理
1.根据当前请求,找到所有能处理请求的handler以及handler的所有拦截器
2.先来顺序执行所有拦截器的prehandle方法
1.如果当前拦截器prohandler返回未true。则执行下一个拦截器。
2.如果当前拦截器返回false, 倒叙执行所有已经执行了的拦截器的 aftercompetition;
3.如果任何一个拦截器返回false。直接跳出不执行目标方法。】
4.所有拦截器都返回true。执行目标方法。
5.倒序执行所有拦截器的posthandle方法
6.只要前面出现异常都会触发aftercompetition;
7.页面渲染完成后也都倒序触发aftercompetition;
public class JWTInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws BusinessException {
String token = request.getHeader("token"); //获取请求头令牌
try {
JWTUtils.verifyToken(token);
} catch (SignatureVerificationException e) {
throw new BusinessException(EmBustinessError.PARAMETER_VALIDATION_ERROR, "无效签名");
} catch (TokenExpiredException e) {
throw new BusinessException(EmBustinessError.PARAMETER_VALIDATION_ERROR, "token过期");
} catch (AlgorithmMismatchException e) {
throw new BusinessException(EmBustinessError.PARAMETER_VALIDATION_ERROR, "算法不一致");
} catch (Exception e) {
throw new BusinessException(EmBustinessError.PARAMETER_VALIDATION_ERROR, "token无效");
}
return true;
}
}
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(new LoginInterceptor())
// .addPathPatterns("/**")
// .excludePathPatterns("/user/**");
registry.addInterceptor(new JWTInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/user/**");
}
}
文件上传
补一个前段知识:多文件上传在表单中添加Multiple就行
后端通过@RequestPart("photo") MultipartFile file【单文件形式】
多文件形式@RequestPart("photos") MultipartFile[] files进行接收。
由于springboot限制了文件上传的大小,所以需要手动设置文件上传的参数
spring:
servlet:
multipart:
max-file-size: 10MB #文件上传的单个不超过10MB
max-request-size: 100MB #总上传文件不能超过100MB
异常处理
原生组件的注入
@servletcomponentscan(basePackages="com.zero"):指定原生servlet组件放在哪里。
@webServlet(urlPatterns="/my"):效果:直接响应,没有经过拦截器
@webFilter(urlpatterns={"/css/","/images/"}):指
@WebListener
@WebServlet(urlPatterns = "/my")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}
@Slf4j
@WebListener //项目启动监听器
public class Mylistener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("项目启动");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("项目销毁");
}
}
@Slf4j
@WebFilter("/file/upload") //制定拦截路径
public class MyFilter extends BaseController implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("myfilter初始化完成");
}
@SneakyThrows
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
log.info("工作");
}
@Override
public void destroy() {
log.info("销毁");
}
}
方式2:
@Configuration(proxyBeanMethods = true) //有组件依赖
public class MyRegisConfig {
@Bean
public ServletRegistrationBean myServlet() {
MyServlet myServlet = new MyServlet();
return new ServletRegistrationBean(myServlet,"/file/upload");
}
@Bean
public FilterRegistrationBean myFilter() {
MyFilter myFilter = new MyFilter();
// return new FilterRegistrationBean(myFilter,myServlet());//拦截servlet路径
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter); //自定义拦截路径
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListenler() {
Mylistener myListener = new Mylistener();
return new ServletListenerRegistrationBean(myListener);
}
}
定制化原理
定制化常见方式
1、修改配置文件
2、xxxxCustomizer;
3、编写自定义的配置类 xxxConfiguration + @Bean替换、增加容器中默认组件;
4、实现webmvcconfigurer
5、@EnableWebMvc + WebMvcConfirurer --@Bean 可以全面接管springMVC,所有的规则都需要自己配置,