文章目录
- 同步请求和异步请求
- 客户端如何发出异步请求
- 自定义模板代码
- Get和Post请求
- 异步版本的注册和登录
- 商品管理系统(异步版本)
- 商品列表步骤:
- 前后端分离
- 为什么需要前后端分离?
- 为什么以后不再使用同步请求?
- JSON
- POJO
- 会话对象Session
- 如何记住登录状态
- 后端的MVC
- 会话管理Cookie
- 通过Cookie实现记住用户名和密码功能
- 过滤器Filter
- timstamp时间类型
- 当表字段的名和VO中的属性名不一致时的解决方案:
同步请求和异步请求
-
同步: 指单线程依次做几件事
-
异步: 指多线程同时做几件事
-
同步请求: 指客户端只有一个主线程, 主线程需要负责页面的渲染操作以及监听操作,如果需要发出请求时,主线程会停止渲染(清空页面) 发出请求, 直到服务器响应了数据之后才会将服务器响应的数据再次渲染出来,这样把原内容清空掉显示新的内容称为页面的整体刷新, 同步请求只能实现整体刷新,无法实现页面的局部刷新
-
异步请求: 指客户端主线程负责页面的渲染和监听,如果需要发出请求时,创建一个新的子线程,由子线程发出请求,请求到数据后把数据呈现在原页面的基础之上, 这种对原页面的部分内容进行改动称为页面的局部刷新, 只有通过异步请求才能实现页面的局部刷新.
客户端如何发出异步请求
- 之前发出请求的方式都是同步请求
- 通过Axios框架发出异步请求
- html页面中引入axios.js框架文件
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
-
相关代码:
//发出异步get请求 axios.get("/helloAxios").then(function (response) { //response是响应对象,response.data得到服务器响应的数据 alert(response.data); v.info=response.data; });
自定义模板代码
Get和Post请求
- Get: 请求参数在请求地址的后面, 由于参数在请求地址当中是可见的所以不能传递带有敏感信息的参数,Get请求参数只能传递几k的数据
- 应用场景: 如果只传递一个参数并且非敏感信息时,一般使用get 因为方便,从字面意思理解get是获取的意思,如果这个请求是查询请求一般也都使用get
- Post:请求参数在请求体里面,参数大小没有限制
- 应用场景: 参数中有敏感信息时,上传文件时, 当传递的参数为多个参数,将多个参数封装到自定义的JS对象里面进行传递时使用Post会更方便
- 应用场景总结: 除了必须使用post的两种情况(1.敏感信息 2.文件上传) 如果传递的参数是2个参数以内 则使用get请求, 如果大于2个参数一般使用post请求, 2个参数时使用两者都可以
异步版本的注册和登录
-
准备工作:
-
创建boot08工程, 勾选3个对勾
-
创建完工程后把mysql的依赖换掉 然后刷新maven
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency>
-
修改application.properties里面连接数据库的信息 url username 和password
-
[
-
在工程中static里面添加index.html首页 首页中准备注册和登录两个超链接
-
-
注册功能:
- 创建reg.html页面, 在页面中通过vue对页面进行管理, 页面中准备三个文本框和一个自定义按钮, 三个文本框和data里面的user对象进行双向绑定, 给按钮添加点击事件, 事件触发时向/reg地址发出异步post请求,并且把v.user传递过去, 服务器返回的值是1代表注册成功显示到首页 否则代表用户名已存在.
- 创建controller.UserController 在里面添加reg方法处理/reg请求, 创建entity.User实体类, 在reg方法的参数列表处声明User对象接收传递过来的参数(不要忘记使用@RequestBody注解修饰), 在方法中调用mapper的selectByUsername方法 通过用户名查询到数据库里面的用户信息, 如果查询到了直接给客户端响应2 代表用户名已存在, 如果没有查询到 调用mapper的insert方法 最后响应1 代表注册成功.
- 创建mapper.UserMapper,里面实现两个方法分别是selectByUsername和insert方法
-
登录步骤:
- 创建login.html页面, 在页面中通过vue对页面进行管理, 页面中准备2个文本框和一个自定义按钮, 2个文本框和data里面的user对象进行双向绑定, 给按钮添加点击事件, 事件触发时向/login地址发出异步post请求,并且把v.user传递过去, 服务器返回的值是1代表登录成功显示到首页如果返回的值是2代表用户名不存在 否则代表密码错误
- 在UserController中添加login方法处理/login请求,参数列表处声明User对象接收传递过来的参数(@RequestBody不要忘记) 在方法中调用mapper的selectByUsername方法, 通过判断分别给客户端响应1,2,3 三种情况
商品管理系统(异步版本)
- 添加商品步骤:
- 在首页里面添加超链接 请求地址 /insert.html
- 创建insert.html页面 通过vue管理页面 ,准备三个文本框 和一个自定义按钮,文本框和变量进行双向绑定, 给按钮添加点击事件, 事件出发时向/insert地址发出异步的post请求,把双向绑定的数据提交给服务器, 响应后弹出添加完成 并返回首页
- 创建ProductController,添加insert方法处理/insert请求, 创建Product实体类,在参数列表处声明 用来接收参数, 不要忘记使用@RequestBody注解, 在方法中调用Mapper的insert方法
- 创建ProductMapper, 里面添加增删改查四个方法(写法和上一个版本的写法一样)
-
商品列表步骤:
前后端分离
为什么需要前后端分离?
- 如果不使用前后端分离设计的话 后端程序员需要准备两套Controller服务于不同的前端(浏览器和手机),这样的话后端的重复性工作量比较大,所以通过前后端分离的方式可以让后端一套Controller服务于任何前端, 这样能够提高后端程序员的开发效率
为什么以后不再使用同步请求?
- 因为前后端分离后, 浏览器端获取页面需要单独发请求获取,请求到页面后再次发出请求获取数据,把得到的数据再展示到页面中, 这就是一个非常典型的页面局部刷新的需求,只有通过异步请求才能实现页面的局部刷新, 同步请求是无法实现的,所以以后工作中只要是前后端分离 就必须使用异步请求.
注册成功!
登录成功!
用户名不存在!
密码错误!
tom:18:男&jerry:20:女
JSON
- JSON是一种轻量级的数据交换格式
- 客户端和服务器之间进行复杂的数据传输时, 如果每次传输都自己定义传输格式的话太影响开发效率, JSON是一种通用的数据交换格式,使用JSON可以大大提高开发效率
[{"name":"tom","age":18,"gender":"男"},
{"name":"jerry","age":20,"gender":"女"}]
话太影响开发效率, JSON是一种通用的数据交换格式,使用JSON可以大大提高开发效率
[{"name":"tom","age":18,"gender":"男"},
{"name":"jerry","age":20,"gender":"女"}]
POJO
- pojo是简单的Java对象, 是entity实体类、值对象VO和数据传输对象DTO的总称
- entity实体类: 通常实体类的属性和表字段是一一对应的
- VO ValueObject值对象: 从数据库里面查询出来的数据 通过值对象对其进行封装
- DTO DataTransferObject数据传输对象: 客户端给服务器传输多个参数时,通过DTO进行封装
会话对象Session
-
服务器会针对每一个客户端在内存中创建一个会话对象, 这个会话对象供同一个客户端的多次请求共享使用, 保存在里面的数据可以给同一个客户端的每一次请求使用.
-
相关方法:
- session.setAttribute(“key”,value); 往会话对象中保存数据
- session.getAttribute(“key”); 从会话对象中获取数据
- session.removeAttribute(“key”); 从会话对象中删除数据
如何记住登录状态
- 客户端登录成功时, 把当前登录的用户对象保存到会话对象里面
- 任何客户端显示首页时都发请求 从会话对象中获取登录成功时保存的用户对象, 如果登录过可以得到用户对象, 如果没有登录过则得到的是个null, 此时就可以通过判断是否拿到了用户对象 来决定当前客户端有没有登录过
后端的MVC
- 将实现一个业务功能的所有代码划分为三部分(包含前端)
- 前端MVC: 是将实现前端业务功能的代码划分为三部分(不包含后端)
- M: Model 模型,指数据模式, 对应的是工程中Mapper相关代码
- V: View 视图, 对应的是工程中前端页面相关代码
- C: Controller控制器, 对应的是工程中Controller相关代码
会话管理Cookie
- 客户端和服务器之间进行数据传输,遵循的是HTTP协议, 此协议是无状态协议(一次请求对应一次响应)响应完之后断开连接, 服务器是无法跟踪客户端的请求的, 通过Cookie技术可一个在客户端第一次请求服务器时服务器给客户端创建一个标识, 之后客户端每次发请求时都会带上这个标识 这样的话服务器就可以识别此客户端了(类似于打孔式的会员卡), 但是由于Cookie的形式数据是保存在客户端的, 存在被篡改的风险, 通过Session可以解决此问题, 因为Session的数据是保存在服务器的(类似于银行卡).
-
通过会话管理技术可以保存服务器和客户端之间的数据(比如让客户端记住用户名和密码,让服务器记住当前客户端的登录状态), 数据库保存的是用户的数据
-
Cookie和Session对比
- Cookie: 数据保存在客户端(类似打孔式的会员卡)
- 保存时间: 默认保存在浏览器的内存中, 当前浏览器关闭时数据会清除,可以设置任意保存时间,设置时间后数据会保存到磁盘中, 时间到了之后自动清除
- 数据类型: 只能保存字符串类型的数据
- 数据量: 由于cookie的数据需要每次发请求时保存在请求头里面,所以数据量只能保存几k的数据
- 应用场景: 需要长时间保存的客户端数据,比如:记住用户名和密码
- Session: 数据保存在服务器(类似银行卡)
- 保存时间: 数据保存在服务器内存中,默认保存半个小时,可以修改时间,但不推荐.(因为服务器只有一个所有客户端的数据都保存在这一个服务器里面这样服务器保存时间太久的话压力太大)
- 数据类型: 可以保存任意对象类型
- 数据量: 没有数据大小的限制,但是不建议保存太大的数据(因为服务器只有一个所有客户端的数据都保存在这一个服务器里面这样服务内存器压力太大)
- 应用场景: 对安全性要求较高的,但是不需要保存时间太久的数据, 比如记住客户端的登录状态
- Cookie: 数据保存在客户端(类似打孔式的会员卡)
通过Cookie实现记住用户名和密码功能
-
在login.html页面添加多选框记住用户名和密码
-
在登录成功时创建Cookie对象把用户名和密码保存到Cookie里面 下发给客户端
- 在login.html页面中 从cookie里面把用户名和密码取出 并赋值给和页面进行绑定的变量
过滤器Filter
-
使用过滤器可以让客户端请求到资源之前或之后 经过过滤器, 这样可以把请求多个资源时执行的相同的代码写在过滤器里面, 这样只需要写一次,起到了代码复用的作用
-
如何使用过滤器:
-
创建Filter.java类文件
-
在XXXAplication.java 类文件中添加 组件扫描注解
-
在过滤器中书写以下代码:
package cn.tedu.coolshark.filter; import cn.tedu.coolshark.pojo.vo.UserVO; import javax.servlet.*; import javax.servlet.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @WebFilter(filterName = "MyFilter", urlPatterns = {"/insertProduct.html","/insertBanner.html","/admin.html","/product/delete"}) public class MyFilter implements Filter { //过滤器初始化方法 public void init(FilterConfig config) throws ServletException { } //过滤器销毁时执行的方法 public void destroy() { } //请求资源之前和之后执行的方法 @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { //因为要用到子类类型中的方法 所以进行类型强转 HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; //从请求对象中获取当前客户端对应的会话对象 HttpSession session = req.getSession(); //从会话对象中获取登录成功时保存的用户对象 UserVO user = (UserVO) session.getAttribute("user"); if (user!=null){//登录过 放行允许客户端请求资源 chain.doFilter(request, response); //请求资源 }else{//未登录 禁止请求资源 并显示登录页面 res.sendRedirect("/login.html"); } } }
-
-
urlPatterns的配置方式:
- 精确匹配: /insertBanner.html /insertProduct.html /product/delete
- 后缀匹配: *.jpg *.html *.xxxx
- 路径匹配: /user/* /product/*
- 全部匹配: /* 匹配网站中所有资源
timstamp时间类型
-
如果数据库表中的某条数据发生改变时,不管改变的是哪一个字段 这个timestamp 类型的数据 会自动修改成当前的系统时间
-
关闭timestamp类型的自动更新功能
use cs;
alter table product change created created timestamp not null default current_timestamp;
-
打开timestamp类型的自动更新功能
alter table product change created created timestamp not null default current_timestamp on update current_timestamp;
当表字段的名和VO中的属性名不一致时的解决方案:
-
查询数据时通过别名的方式解决(不能复用)
-
如果不一致仅仅是因为命名规范不一致的情况下, 在application.properties里面添加以下配置即可解决
mybatis.configuration.map-underscore-to-camel-case=true
-
通过resultMap手动映射的方式解决(可以复用)