Web
Web:全球广域网,也称为万维网,能够通过浏览器访问的网站
Web的工作流程
SpringBootWeb入门
- 在创建SpringBoot项目后,添加web相关依赖
- 创建请求处理类HelloConrtoller和请求处理方法hello
HTTP协议
概念: 超文本传输协议(Hyper Text Transfer Protocol),规定了浏览器与服务器之间数据传输的规则
一次请求的请求和响应
特点:
-
基于TCP协议:面向连接,安全(需要经历三次握手四次挥手)
-
基于请求-响应模型的:一次请求对应一次响应
-
HTTP协议是无状态的协议:对于事务处理没有记忆能力。每次请求-响应都是独立的。
- 缺点:多次请求间不能共享数据。
- 优点:速度快
HTTP-请求数据格式
请求头信息
请求方式GET和POST的区别
请求方式 | 区别 |
---|---|
GET | 请求参数在请求行中,没有请求体,如:/brand/findAll?name=OPPO&status=1。GET请求大小是有限制的。 |
POST | 请求参数在请求体中,POST请求大小是没有限制的。 |
HTTP-相应格式
响应头格式
常见响应码
HTTP协议解析
客户端可以根据响应的内容转换为具体的数据
那在服务器端如何解析http的数据,并且给浏览器响应数据呢?
按照tcp网络编程,可以使用socket/server socket接收浏览器发送的请求,按照字符串的规则解析,并按照输出流给出固定格式的字符串
如下:
Web服务器-Tomcat
Web服务器:
- 对HTTP协议操作进行封装,简化web程序开发
- 部署web项目,对外提供网上信息浏览服务
Tomcat:
- 一个轻量级的web服务器,支持servlet、jsp等少量JavaEE规范
- 也被称为web容器、servlet容器
- 官网:tomcat.apache.org/
Tomcat入门程序解析(内嵌tomcat)
- 起步依赖: springboot官网提供的用来简化配置的,用一个依赖相当于整块业务开发的全部依赖,原理是maven传递
起步依赖的版本都有父工程统一管理
-
内嵌tomcat服务器:基于Springboot开发的web应用程序,内置了tomcat服务器,当启动类运行时,会自动启动内嵌的tomcat服务器。
运行启动类启动springboot的过程中,会自动将内嵌的tomcat也启动起来,并且默认占用tomcat的端口号8080。
在浏览器访问地址时,就会访问到内嵌的tomcat,并且访问到部署在tomcat内部的程序,拿到响应结果
请求响应
在浏览器输入地址会将请求打到对应Web服务器上,Tomcat可以识别HTTP协议的请求数据,并响应数据给浏览器。开发将具体业务逻辑写在各个Controller层中,但Tomcat不能识别编写的controller,它识别Servlet,SpringBoot底层提供了一个核心的前端控制器DispatcherServlet
Servlet中有两个对象:HttpServletRequest和HttpServletResponse
Tomcat将请求的数据转成HttpServletRequest数据,并根据HttpServletResponse对象设置的响应信息来响应数据给浏览器
- 请求(HttpServletRequest):获取请求数据
- 响应(HttpServletResponse):设置响应数据
- BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。不需要单独下载,维护方便,体验一般
- CS架构:Client/Server,客户端/服务器架构模式。是需要下载客户端的,开发、维护麻烦,体验不错
请求
简单参数
-
原始方式获取请求参数
- Controller方法形参中声明HttpServletRequest对象
- 调用对象的getParameter(参数名)
-
SpringBoot接收简单参数
- 请求参数名与方法形参变量名相同
- 会自动进行类型转换
-
@RequestParam注解
- 方法形参名称与请求参数名称不匹配,通过该注解完成映射
- 该注解的required属性默认是true,代表请求参数必须传递
实体参数
请求参数名与形参对象属性名相同,即可直接通过POJO接收
复杂实体对象:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POO属性参数。
数组集合参数
-
数组:请求参数名与形参中数组变量名相同,可以直接使用数组封装
-
集合:请求参数名与形参中集合变量名相同,通过
@RequestParam
绑定参数关系,如果不加注解,会自动转为数组形式
日期参数
使用@DateTimeFormat
注解完成日期参数格式转换
JSON参数
JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用@RequestBody
表示
路径参数
通过请求URL直接传递参数,使用{...}来标识该路径参数,需要使用@PathVariable
获取路径参数
响应
@ResponseBody
- 类型:方法注解、类注解
- 位置:Controller方法上/类上
- 作用:将方法返回值直接响应,如果返回值类型是实体对象/集合,就会转换为JSON格式响应
- 说明:
@RestController=@Controller+@ResponseBody
统一响应结果
分层解耦
三层架构
- controller:控制层,接受前端发送的请求,对请求进行处理,并响应数据
- service:业务逻辑层,处理具体的业务逻辑
- dao:数据访问层/持久层Data Access Object,负责数据访问操作,包括数据的增、删、改、查
分层解耦
- 控制反转:Inversion Of Control,简称lOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转
- 依赖注入:Dependency Injection,简称Dl。容器为应用程序提供运行时所依赖的资源,称之为依赖注入。
- Bean对象:IOC容器中创建、管理的对象,称之为bean
IOC详解
要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一
注解 | 说明 | 位置 |
---|---|---|
@Component | 声明bean的基础注解 | 不属于以下三类时,用此注解 |
@Controller | @Component的衍生注解 | 标注在控制器类上 |
@Service | @Component的衍生注解 | 标注在业务类上 |
@Repository | @Component的衍生注解 | 标注在数据访问类上(由于与mybatis整合,用的比较少) |
- 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
- 使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。
Bean组件扫描
- 声明bean的四大注解想要生效,还需要被组件扫描注解
@ComponentScan
扫描 - 在SpringBoot启动类中
@SpringBootApplication
注解中包含了@ComponentScan
,默认扫描的范围时启动类所在包及其子包
DI详解
使用@Autowired
注解实现注入。如果同类型的bean存在多个,可以使用:
- @Primary
- @Autowired+@Qualifier("bean的名称")
- @Resource(name="bean的名称")
@Resource与@Autowired区别
- @Autowired是spring框架提供的注解,而@Resource是JDK提供的注解。
- @Autowired默认是按照类型注入,而@Resource默认是按照名称注入。
登录校验
会话技术
-
会话: 用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应
-
会话跟踪: 一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据
-
会话跟踪方案
- 客户端会话跟踪技术:Cookie
- 服务端会话跟踪技术:Session
- 令牌技术
会话跟踪方案对比
JWT
-
场景:登录认证
- 登陆成功后,生成令牌
- 后续每个请求,都要携带JWT令牌,系统在每次请求处理之前,先校验令牌,通过后,再处理
生成JWT后,将JWT返回给前端,前端会将token存入到浏览器的本地存储空间中,该存储空间不论是移动端还是客户端都有
过滤器Filter
- 概念:Filter过滤器,是JavaWeb三大组件(Servlet、Filter、Listener)之一。
- 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
- 过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。
入门使用:
- 定义Filter:定义一个类,实现Filter接口,并重写其所有方法。
- 配置Filter:Filter类上加@WebFilter注解,配置拦截资源的路径。引导类上加@ServletComponentScan开启Servlet组件支持。
java
/**
* Filter 属于JavaWeb三大组件之一
* 并非SpringBoot提供的功能
* 要想在SpringBoot中使用JavaWeb的组件,需要在启动类添加注解@ServletComponentScan
* @ServletComponentScan:该注解表示开启了对servlet组件的支持
*/
@WebFilter(urlPatterns = "/*")//拦截请求的路径 /*表示拦截所有
public class DemoFilter implements Filter {
//初始化方法,只调用一次
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init 初始方法执行了");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截到了请求");
//放行
filterChain.doFilter(servletRequest, servletResponse);
}
//销毁方法,只调用一次
@Override
public void destroy() {
System.out.println("destroy 销毁方法执行了");
}
}
Filter执行流程
请求------>放行前逻辑------>放行------>资源------>放行后逻辑
Filter拦截路径
过滤器链
- 介绍:一个wb应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链。
- 顺序:注解配置的Filter,优先级是按照过滤器类名(字符串)的自然排序。
登录校验Filter流程
ini
@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) request;
//1.获取请求url
String url = req.getRequestURL().toString();
System.out.println(url);
//2.判断url是否包含login关键字,如果包含,就放行,走登录逻辑
if (url.contains("login")){
log.info("登录操作,放行。。。");
chain.doFilter(request, response);
return;
}
//3.获取请求头中的令牌
String jwt = req.getHeader("token");
//4.判断令牌是否存在,不存在则返回错误信息
if (!StringUtils.hasLength(jwt)){
log.info("请求头token为null,返回未登陆的信息");
Result notLogin = Result.error("NOT_LOGIN");
//手动转换对象------>json,使用阿里巴巴的fastJSON
String jsonString = JSONObject.toJSONString(notLogin);
resp.getWriter().write(jsonString);
return;
}
//5.解析token,如果解析失败,返回错误结果
try {
JwtUtils.parseJWT(jwt);
}catch (Exception e){
log.info("解析令牌失败");
Result notLogin = Result.error("NOT_LOGIN");
//手动转换对象------>json,使用阿里巴巴的fastJSON
String jsonString = JSONObject.toJSONString(notLogin);
resp.getWriter().write(jsonString);
return;
}
//6.放行
log.info("令牌合法,放行");
chain.doFilter(request, response);
}
}
拦截器Intercrptor
- 概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。
- 作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。
入门使用
定义拦截器
java
@Slf4j
@Component //将其交给IOC容器管理
public class LoginCheckInterceptor implements HandlerInterceptor {
//目标资源方法运行前运行, 返回true: 放行, 放回false, 不放行
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
System.out.println("preHandle ... ");
return true;
}
//目标资源方法运行后运行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle ...");
}
//视图渲染完毕后运行, 最后运行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
注册拦截器
typescript
@Configuration //配置类
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
}
}
拦截器-拦截路径
拦截器-执行流程
Filter和Interceptor的区别
- 接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。
- 拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。