1 前端三件套

1.1 HTML

HTML文件本质上是文本文件,而普通的文本文件只能显示字符。但是HTML技术则通过HTML标签把其他网页、图片、音频、视频等各种多媒体资源引入到当前网页中,让网页有了非常丰富的呈现方式,这就是超文本的含义——本身是文本,但是呈现出来的最终效果超越了文本。说HTML是一种『标记语言』是因为它不是向Java这样的『编程语言』,因为它是由一系列『标签』组成的,没有常量、变量、流程控制、异常处理、IO等等这些功能。HTML很简单,每个标签都有它固定的含义和确定的页面显示效果。

1.2 CSS

CSS 指层叠样式表 (Cascading Style Sheets);样式定义如何显示 HTML 元素样式通常存储在样式表中;把样式添加到 HTML 4.0 中,是为了解决内容与表现分离的问题;外部样式表可以极大提高工作效率;外部样式表通常存储在 CSS 文件中;多个样式定义可层叠为一个;样式表定义如何显示 HTML 元素,就像 HTML 中的字体标签和颜色属性所起的作用那样。样式通常保存在外部的 .css 文件中。我们只需要编辑一个简单的 CSS 文档就可以改变所有页面的布局和外观。

  • CSS的角色:页面显示的美观风格
  • CSS的基础语法:标签样式;类样式;ID样式;组合样式;嵌入式样式表;内部样式表;外部样式表
  • 盒子模型:border、margin、padding
  • 定位和浮动:position、float、DIV+CSS布局

1.3 JavaScript

JavaScript 是 Web 的编程语言。所有现代的 HTML 页面都可以使用 JavaScript。
JavaScript是一种解释型的脚本语言。不同于C、C++、Java等语言先编译后执行, JavaScript不会产生编译出来的字节码文件,而是在程序的运行过程中对源文件逐行进行解释。

  • JS是客户端(浏览器端)运行的脚本语言,语法风格和java比较类似
  • JS是弱类型的语言 var str = 99 ;
  • JS的函数 function hello(var num){}
  • DOM技术:
    • 鼠标悬浮:onmouseover,event.srcElement,事件传递,parentElement,style.backgroundColor
    • 鼠标离开:onmouseout
    • 鼠标点击:hand/pointer,onclick , td.innerText , td.innerHTML=“”, td.firstChild.value=oldPrice
    • 失去焦点:onblur , input.parentElement.innerText = newPrice ;
    • 更新小计:input = event.srcElement , tr = input.parentElement.parentElement ; tr.cells , parseInt
    • 更新总计:document.getElementById(“fruit_tbl”) , fruitTbl.rows
    • 删除一行:img , img.parentElement.parentElement.rowIndex , table.deleteRow(rowIndex)
  • JavaScript 控制了网页的行为
    JavaScript 是 web 开发人员必须学习的 3 门语言中的一门:
    1 HTML 定义了网页的内容
    2 CSS 描述了网页的布局
    3 JavaScript 控制了网页的行为
    在这里插入图片描述

2 Tomcat

2.1 BS和CS

请添加图片描述

2.2 tomcat扮演的角色

在这里插入图片描述

2.3 tomcat部署

tomcat8之前,设置编码:
1)get请求方式:
//get方式目前不需要设置编码(基于tomcat8)
//如果是get请求发送的中文数据,转码稍微有点麻烦(tomcat8之前)
String fname = request.getParameter(“fname”);
//1.将字符串打散成字节数组
byte[] bytes = fname.getBytes(“ISO-8859-1”);
//2.将字节数组按照设定的编码重新组装成字符串
fname = new String(bytes,“UTF-8”);
2)post请求方式:
request.setCharacterEncoding(“UTF-8”);
tomcat8开始,设置编码,只需要针对post方式
request.setCharacterEncoding(“UTF-8”);
注意:
需要注意的是,设置编码(post)这一句代码必须在所有的获取参数动作之前

3 Servlet

3.1 简介

  • Servlet=Server+applet,Servlet含义是服务器端的小程序
  • 在整个Web应用中,Servlet主要负责处理请求、协调调度功能。我们可以把Servlet称为Web应用中的『控制器』

3.2 Servlet的继承关系 - 重点查看的是服务方法(service())

3.2.1 继承关系
javax.servlet.Servlet接口
  javax.servlet.GenericServlet抽象类
    javax.servlet.http.HttpServlet抽象子类
3.2.2 相关方法
javax.servlet.Servlet接口:
    void init(config) - 初始化方法
    void service(request,response) - 服务方法
    void destory() - 销毁方法

javax.servlet.GenericServlet抽象类:
    void service(request,response) - 仍然是抽象的

javax.servlet.http.HttpServlet 抽象子类:
    void service(request,response) - 不是抽象的

1 String method = req.getMethod(); 获取请求的方式
2. 各种if判断,根据请求方式不同,决定去调用不同的do方法
if (method.equals(“GET”)) {
this.doGet(req,resp);
} else if (method.equals(“HEAD”)) {
this.doHead(req, resp);
} else if (method.equals(“POST”)) {
this.doPost(req, resp);
} else if (method.equals(“PUT”)) {
3. 在HttpServlet这个抽象类中,do方法都差不多:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString(“http.method_get_not_supported”);
if (protocol.endsWith(“1.1”)) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}

3.2.3 小结
1) 继承关系: HttpServlet -> GenericServlet -> Servlet
2) Servlet中的核心方法: init() , service() , destroy()
3) 服务方法: 当有请求过来时,service方法会自动响应(其实是tomcat容器调用的)
        在HttpServlet中我们会去分析请求的方式:到底是get、post、head还是delete等等
        然后再决定调用的是哪个do开头的方法
        那么在HttpServlet中这些do方法默认都是405的实现风格-要我们子类去实现对应的方法,否则默认会报405错误
4) 因此,我们在新建Servlet时,我们才会去考虑请求方法,从而决定重写哪个do方法

注意Servlet是线程不安全

在这里插入图片描述

3.3 Servlet生命周期

1) 生命周期:从出生到死亡的过程就是生命周期。对应Servlet中的三个方法:init(),service(),destroy()
2) 默认情况下:
    第一次接收请求时,这个Servlet会进行实例化(调用构造方法)、初始化(调用init())、然后服务(调用service())
    从第二次请求开始,每一次都是服务
    当容器关闭时,其中的所有的servlet实例会被销毁,调用销毁方法
3) 通过案例我们发现:
    - Servlet实例tomcat只会创建一个,所有的请求都是这个实例去响应。
    - 默认情况下,第一次请求时,tomcat才会去实例化,初始化,然后再服务.这样的好处是什么? 提高系统的启动速度 。 这样的缺点是什么? 第一次请求时,耗时较长。
    - 因此得出结论: 如果需要提高系统的启动速度,当前默认情况就是这样。如果需要提高响应速度,我们应该设置Servlet的初始化时机。
4) Servlet的初始化时机:
    - 默认是第一次接收请求时,实例化,初始化
    - 我们可以通过<load-on-startup>来设置servlet启动的先后顺序,数字越小,启动越靠前,最小值0
5) Servlet在容器中是:单例的、线程不安全的
    - 单例:所有的请求都是同一个实例去响应
    - 线程不安全:一个线程需要根据这个实例中的某个成员变量值去做逻辑判断。但是在中间某个时机,另一个线程改变了这个成员变量的值,从而导致第一个线程的执行路径发生了变化
    - 我们已经知道了servlet是线程不安全的,给我们的启发是: 尽量的不要在servlet中定义成员变量。如果不得不定义成员变量,那么不要去:①不要去修改成员变量的值 ②不要去根据成员变量的值做一些逻辑判断

3.4 HTTP

  • Http 称之为超文本传输协议
  • Http是无状态的
  • Http请求响应包含两个部分:请求和响应

请求:
请求包含三个部分: 1.请求行 ; 2.请求消息头 ; 3.请求主体
1)请求行包含是三个信息: 1. 请求的方式 ; 2.请求的URL ; 3.请求的协议(一般都是HTTP1.1)
2)请求消息头中包含了很多客户端需要告诉服务器的信息,比如:我的浏览器型号、版本、我能接收的内容的类型、我给你发的内容的类型、内容的长度等等
3)请求体,三种情况
get方式,没有请求体,但是有一个queryString
post方式,有请求体,form data
json格式,有请求体,request payload
4)HTTP协议已定义的请求方式
HTTP1.1中共定义了八种请求方式:
GET:从服务器端获取数据
POST:将数据保存到服务器端
PUT:命令服务器对数据执行更新
DELETE:命令服务器删除数据
HEAD
CONNECT
OPTIONS
TRACE
响应:
响应也包含三本: 1. 响应行 ; 2.响应头 ; 3.响应体
1)响应行包含三个信息:1.协议 2.响应状态码(200) 3.响应状态(ok)
2)响应头:包含了服务器的信息;服务器发送给浏览器的信息(内容的媒体类型、编码、内容长度等)
3)响应体:响应的实际内容(比如请求add.html页面时,响应的内容就是<form…)
4)响应状态码
作用:以编码的形式告诉浏览器当前请求处理的结果

常见的响应状态码

状态码含义
200服务器成功处理了当前请求,成功返回响应
302重定向
400[SpringMVC特定环境]请求参数问题
403没有权限
404找不到目标资源
405请求方式和服务器端对应的处理方式不一致
406[SpringMVC特定环境]请求扩展名和实际返回的响应体类型不一致
50X服务器端内部错误,通常都是服务器端抛异常了

404产生的具体原因:
访问地址写错了,确实是没有这个资源
访问了WEB-INF目录下的资源
Web应用启动的时候,控制台已经抛出异常,导致整个Web应用不可用,访问任何资源都是404
服务器端缓存

3.5 会话

1) Http是无状态的

  • HTTP 无状态 :服务器无法判断这两次请求是同一个客户端发过来的,还是不同的客户端发过来的
  • 无状态带来的现实问题:第一次请求是添加商品到购物车,第二次请求是结账;如果这两次请求服务器无法区分是同一个用户的,那么就会导致混乱
  • 通过会话跟踪技术来解决无状态的问题。

2) 会话跟踪技术

  • 客户端第一次发请求给服务器,服务器获取session,获取不到,则创建新的,然后响应给客户端

  • 下次客户端给服务器发请求时,会把sessionID带给服务器,那么服务器就能获取到了,那么服务器就判断这一次请求和上次某次请求是同一个客户端,从而能够区分开客户端

  • 常用的API:

    request.getSession() -> 获取当前的会话,没有则创建一个新的会话
    request.getSession(true) -> 效果和不带参数相同
    request.getSession(false) -> 获取当前会话,没有则返回null,不会创建新的

    session.getId() -> 获取sessionID
    session.isNew() -> 判断当前session是否是新的
    session.getMaxInactiveInterval() -> session的非激活间隔时长,默认1800秒
    session.setMaxInactiveInterval()
    session.invalidate() -> 强制性让会话立即失效

    在这里插入图片描述

3) session保存作用域

  • session保存作用域是和具体的某一个session对应的
  • 常用的API:
    void session.setAttribute(k,v)
    Object session.getAttribute(k)
    void removeAttribute(k)
    在这里插入图片描述

原始情况下,保存作用域我们可以认为有四个: page(页面级别,现在几乎不用) , request(一次请求响应范围) , session(一次会话范围) , application(整个应用程序范围)
1) request:一次请求响应范围
2) session:一次会话范围有效
3) application: 一次应用程序范围有效

在这里插入图片描述

request保存作用域

在这里插入图片描述

session保存作用域

在这里插入图片描述

application保存作用域

3.6 服务器内部转发以及客户端重定向

1) 服务器内部转发 : request.getRequestDispatcher(“…”).forward(request,response);

  • 一次请求响应的过程,对于客户端而言,内部经过了多少次转发,客户端是不知道的
  • 地址栏没有变化
    在这里插入图片描述

2) 客户端重定向: response.sendRedirect(“…”);

  • 两次请求响应的过程。客户端肯定知道请求URL有变化
  • 地址栏有变化
    在这里插入图片描述

3.7 Thymeleaf - 视图模板技术

官方地址
1) 添加thymeleaf的jar包
2) 新建一个Servlet类ViewBaseServlet
3) 在web.xml文件中添加配置

  • 配置前缀 view-prefix
  • 配置后缀 view-suffix

4) 使得我们的Servlet继承ViewBaseServlet
5) 根据逻辑视图名称 得到 物理视图名称

  • 此处的视图名称是 index
  • 那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
  • 逻辑视图名称 : index
  • 物理视图名称 : view-prefix + 逻辑视图名称 + view-suffix
  • 所以真实的视图名称是: / index .html

super.processTemplate(“index”,request,response);
6)使用thymeleaf的标签
th:if , th:unless , th:each , th:text
7) 相对路径和绝对路径
在这里插入图片描述

4 MVC

4.1 没用MVC之前,我们处理业务逻辑

(以水果库存系统为例)

  1. 最初的做法是: 一个请求对应一个Servlet,这样存在的问题是servlet太多了
  2. 把一些列的请求都对应一个Servlet, IndexServlet/AddServlet/EditServlet/DelServlet/UpdateServlet -> 合并成FruitServlet
    通过一个operate的值来决定调用FruitServlet中的哪一个方法
    使用的是switch-case
  3. 在上一个版本中,Servlet中充斥着大量的switch-case,试想一下,随着我们的项目的业务规模扩大,那么会有很多的Servlet,也就意味着会有很多的switch-case,这是一种代码冗余
    因此,我们在servlet中使用了反射技术,我们规定operate的值和方法名一致,那么接收到operate的值是什么就表明我们需要调用对应的方法进行响应,如果找不到对应的方法,则抛异常
  4. 在上一个版本中我们使用了反射技术,但是其实还是存在一定的问题:每一个servlet中都有类似的反射技术的代码。因此继续抽取,设计了中央控制器类:DispatcherServlet
    DispatcherServlet这个类的工作分为两大部分:
    a. 根据url定位到能够处理这个请求的controller组件:
    1)从url中提取servletPath : /fruit.do -> fruit
    2)根据fruit找到对应的组件:FruitController , 这个对应的依据我们存储在applicationContext.xml中
    <bean id=“fruit” class="com.atguigu.fruit.controllers.FruitController/>
    通过DOM技术我们去解析XML文件,在中央控制器中形成一个beanMap容器,用来存放所有的Controller组件
    3)根据获取到的operate的值定位到我们FruitController中需要调用的方法
    b. 调用Controller组件中的方法:
    1) 获取参数
    获取即将要调用的方法的参数签名信息: Parameter[] parameters = method.getParameters();
    通过parameter.getName()获取参数的名称;
    准备了Object[] parameterValues 这个数组用来存放对应参数的参数值
    另外,我们需要考虑参数的类型问题,需要做类型转化的工作。通过parameter.getType()获取参数的类型
    2) 执行方法
    Object returnObj = method.invoke(controllerBean , parameterValues);
    3) 视图处理
    String returnStr = (String)returnObj;
    if(returnStr.startWith(“redirect:”)){

    }else if…

在这里插入图片描述

一个请求对应一个Servlet

在这里插入图片描述

合并Servlet

4.2 什么是业务层

  1. Model1和Model2
    MVC : Model(模型)、View(视图)、Controller(控制器)
    视图层:用于做数据展示以及和用户交互的一个界面
    控制层:能够接受客户端的请求,具体的业务功能还是需要借助于模型组件来完成
    模型层:模型分为很多种:有比较简单的pojo/vo(value object),有业务模型组件,有数据访问层组件
    1) pojo/vo : 值对象
    2) DAO : 数据访问对象
    3) BO : 业务对象
    在这里插入图片描述
库存系统使用上MVC之后
  1. 区分业务对象和数据访问对象:
    1) DAO中的方法都是单精度方法或者称之为细粒度方法。什么叫单精度?一个方法只考虑一个操作,比如添加,那就是insert操作、查询那就是select操作…
    2) BO中的方法属于业务方法,也实际的业务是比较复杂的,因此业务方法的粒度是比较粗的
    注册这个功能属于业务功能,也就是说注册这个方法属于业务方法。
    那么这个业务方法中包含了多个DAO方法。也就是说注册这个业务功能需要通过多个DAO方法的组合调用,从而完成注册功能的开发。
    注册:

    检查用户名是否已经被注册 - DAO中的select操作
    向用户表新增一条新用户记录 - DAO中的insert操作
    向用户积分表新增一条记录(新用户默认初始化积分100分) - DAO中的insert操作
    向系统消息表新增一条记录(某某某新用户注册了,需要根据通讯录信息向他的联系人推送消息) - DAO中的insert操作
    向系统日志表新增一条记录(某用户在某IP在某年某月某日某时某分某秒某毫秒注册) - DAO中的insert操作

  2. 在库存系统中添加业务层组件
    在这里插入图片描述

4.3 IOC

1. 耦合/依赖
  依赖指的是某某某离不开某某某
  在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。
  我们系统架构或者是设计的一个原则是: 高内聚低耦合。
  层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的,最理想的情况0耦合(就是没有耦合)
2. IOC - 控制反转 / DI - 依赖注入
    控制反转:
1) 之前在Servlet中,我们创建service对象 , FruitService fruitService = new FruitServiceImpl();
   这句话如果出现在servlet中的某个方法内部,那么这个fruitService的作用域(生命周期)应该就是这个方法级别;
   如果这句话出现在servlet的类中,也就是说fruitService是一个成员变量,那么这个fruitService的作用域(生命周期)应该就是这个servlet实例级别
2) 之后我们在applicationContext.xml中定义了这个fruitService。然后通过解析XML,产生fruitService实例,存放在beanMap中,这个beanMap在一个BeanFactory中
   因此,我们转移(改变)了之前的service实例、dao实例等等他们的生命周期。控制权从程序员转移到BeanFactory。这个现象我们称之为控制反转

   依赖注入:
1) 之前我们在控制层出现代码:FruitService fruitService = new FruitServiceImpl();
   那么,控制层和service层存在耦合。
2) 之后,我们将代码修改成FruitService fruitService = null ;
   然后,在配置文件中配置:
   <bean id="fruit" class="FruitController">
        <property name="fruitService" ref="fruitService"/>
   </bean>

这部分内容在框架中需要进一步学习

4.4 过滤器Filter

  1. Filter也属于Servlet规范
  2. Filter开发步骤:新建类实现Filter接口,然后实现其中的三个方法:init、doFilter、destroy
    配置Filter,可以用注解@WebFilter,也可以使用xml文件
  3. Filter在配置时,和servlet一样,也可以配置通配符,例如 @WebFilter(“*.do”)表示拦截所有以.do结尾的请求
  4. 过滤器链
    1)执行的顺序依次是: A B C demo03 C2 B2 A2
    2)如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的
    3)如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序
  5. 过滤器的三要素

①拦截
过滤器之所以能够对请求进行预处理,关键是对请求进行拦截,把请求拦截下来才能够做后续的操作。而且对于一个具体的过滤器,它必须明确它要拦截的请求,而不是所有请求都拦截。
②过滤
根据业务功能实际的需求,看看在把请求拦截到之后,需要做什么检查或什么操作,写对应的代码即可。
③放行
过滤器完成自己的任务或者是检测到当前请求符合过滤规则,那么可以将请求放行。所谓放行,就是让请求继续去访问它原本要访问的资源。

  1. Filter生命周期
    和Servlet生命周期类比,Filter生命周期的关键区别是:在Web应用启动时创建对象
生命周期执行时间执行次数
创建对象Web应用启动时一次
初始化创建对象后一次
拦截请求接收到匹配的请求多次
销毁Web应用卸载前一次

过滤器经典运用:处理编码问题
在这里插入图片描述

4.5 事务管理

事务是一组原子操作单元,从数据库角度说,就是一组SQL指令,要么全部执行成功,若因为某个原因其中一条指令执行有错误,则撤销先前执行过的所有指令。更简答的说就是:要么全部执行成功,要么撤销不执行。

  • 原子性(atomicity):原子性表示事务执行过程中的任何失败都将导致事务所做的任何修改失效。
  • 一致性(consistency):一致性表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态。
  • 隔离性(isolation):隔离性表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见。
  • 持久性(durability):持久性表示已提交的数据在事务执行失败时,数据的状态都应该正确。
  1. 涉及到的组件:

    • OpenSessionInViewFilter
    • TransactionManager
    • ThreadLocal
    • ConnUtil
    • BaseDAO
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
    1. ThreadLocal
      在这里插入图片描述
    • get() , set(obj)
    • ThreadLocal称之为本地线程 。 我们可以通过set方法在当前线程上存储数据、通过get方法在当前线程上获取数据
    • set方法源码分析:
      public void set(T value) {
      Thread t = Thread.currentThread(); //获取当前的线程
      ThreadLocalMap map = getMap(t); //每一个线程都维护各自的一个容器(ThreadLocalMap)
      if (map != null)
      map.set(this, value); //这里的key对应的是ThreadLocal,因为我们的组件中需要传输(共享)的对象可能会有多个(不止Connection)
      else
      createMap(t, value); //默认情况下map是没有初始化的,那么第一次往其中添加数据时,会去初始化
      }
      -get方法源码分析:
      public T get() {
      Thread t = Thread.currentThread(); //获取当前的线程
      ThreadLocalMap map = getMap(t); //获取和这个线程(企业)相关的ThreadLocalMap(也就是工作纽带的集合)
      if (map != null) {
      ThreadLocalMap.Entry e = map.getEntry(this); //this指的是ThreadLocal对象,通过它才能知道是哪一个工作纽带
      if (e != null) {
      @SuppressWarnings(“unchecked”)
      T result = (T)e.value; //entry.value就可以获取到工具箱了
      return result;
      }
      }
      return setInitialValue();
      }

4.6 监听器

4.6.1 概述

专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。 Servlet监听器:Servlet规范中定义的一种特殊类,它用于监听Web应用程序中的ServletContext,HttpSession 和HttpServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。

4.6.2 监听器列表
  1. ServletContextListener - 监听ServletContext对象的创建和销毁的过程
  2. HttpSessionListener - 监听HttpSession对象的创建和销毁的过程
  3. ServletRequestListener - 监听ServletRequest对象的创建和销毁的过程
  4. ServletContextAttributeListener - 监听ServletContext的保存作用域的改动(add,remove,replace)
  5. HttpSessionAttributeListener - 监听HttpSession的保存作用域的改动(add,remove,replace)
  6. ServletRequestAttributeListener - 监听ServletRequest的保存作用域的改动(add,remove,replace)
  7. HttpSessionBindingListener - 监听某个对象在Session域中的创建与移除
  8. HttpSessionActivationListener - 监听某个对象在Session域中的序列化和反序列化

4.7 MVC各个层的设计

在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐