后端学习 - JavaWeb

技术体系

在这里插入图片描述

文章目录

  • 一 HTML
    • 1 网页的组成部分
    • 2 HTML 概述
    • 3 HTML 标签
    • 4 常用标签
    • 5 表单与表单的提交
  • 二 CSS
    • 1 语法格式
    • 2 使用方法
  • 三 JavaScript
    • 1 概述
    • 2 与 HTML 结合的两种方式
    • 3 变量类型及特殊值
    • 4 关系、逻辑运算
    • 5 数组
    • 6 函数
    • 7 事件
    • 8 DOM (Document Object Model)
    • 9 DOM实例:验证用户名是否有效
  • 四 Tomcat
  • 五 Servlet
    • 1 举例:向数据库中添加表单信息
    • 2 Servlet 的继承关系
    • 3 Servlet 的生命周期
    • 4 HTTP 协议与 Session会话跟踪
    • 5 服务器端内部转发、重定向
    • 6 Servlet 保存作用域
    • 7 Servlet 的 init 方法与初始化参数设置
    • 8 ServletContext
  • 六 Thymeleaf
    • 1 配置过程
    • 2 Servlet 优化 - 合并同类方法
    • 3 Servlet 优化 - dispatchedServlet
  • 七 MVC
    • 1 概念
    • 2 降低各层间的耦合 - IOC 与 DI
    • 3 IOC 与 DI 的实现过程
  • 八 Filter
    • 1 概述
    • 2 使用 Filter 实现事务的原子性
  • 九 Listener
  • 十 总结

一 HTML

1 网页的组成部分

  • 内容(结构):在页面中可以看到的数据。我们称之为内容。一般使用 HTML 技术展示。
  • 表现:内容在页面上的展示形式,比如布局,颜色,大小等等。一般使用CSS 技术实现。
  • 行为:页面中元素与输入设备交互的响应。一般使用 JavaScript 技术实现。

2 HTML 概述

  • Hyper Text Markup Language (超文本标记语言),网页文件本身是一种文本文件,通过在文本文件中添加标记符,可以告诉浏览器如何显示其中的内容。
  • HTML 文件不需要编译,直接由浏览器进行解析执行。
  • 书写规范:大致由 head 和 body 两部分组成。
<html lang="en">  <!-- 页面开始 --><head>  <!-- HEAD --><meta charset="UTF-8"><title> 我的标题 </title></head><body>  <!-- BODY -->hello!</body></html>  <!-- 页面结束 -->

3 HTML 标签

  • 标签名对大小写不敏感。
  • 双标签的格式:<标签名> 封装的数据 </标签名>
    单标签的格式:<标签名/>
  • 标签拥有自己的属性,分为基本属性和事件属性。属性必须有值,属性值必须加引号。
  • 双标签必须正确关闭,不能交叉嵌套。
  • 想显示“转义字符”的问题(比如想打印出左尖括号<),用实体名称解决(对应的实体名称是&lt;)。
    <body onclick="alert('警告')">  <!-- 带有事件属性 -->点击body部分会出现警告 <hr/>  <!-- 单标签 --><font color="blue"> 蓝色的字体 </font>  <!-- 双标签,带有基本属性 --></body>

4 常用标签

重点是超链接、表格、表单

<!--标题标签,最大是h1,最小是h6,对齐可以选择 left/ center/ right-->
<h1 align="center"> 标题 </h1><!--字体-->
<font color="red" size="7"> 字体 </font><!--超链接,可选参数 target (_self 在当前页面跳转,_blank 在新页面跳转...)-->
<a href="www.baidu.com" target="_blank"> 超链接 </a><!--无序列表(有序将ul改为ol)-->
<ul><li> item1 </li><li> item2 </li>
</ul><!--图片img标签是图片标签,用来显示图片src属性可以设置图片的路径width属性设置图片的宽度height属性设置图片的高度border属性设置图片边框大小alt属性设置当指定路径找不到图片时,用来代替显示的文本内容绝对路径的正确格式是:  http://ip:port/工程名/资源路径
-->
<img src="./imgs/1.jpg" width="100" height="200"/><!--表格table 标签是表格标签border 设置表格标签width 设置表格宽度height 设置表格高度align 设置表格相对于页面的对齐方式cellspacing 设置单元格间距tr	是行标签th	是表头标签td  是单元格标签align 设置单元格文本对齐方式b 是加粗标签如果要实现跨行、跨列,改变 td 的 colspan、rowspan 属性
-->
<table align="center" border="1" width="300" height="300" cellspacing="0"><tr><th>1.1</th><th>1.2</th><th>1.3</th></tr><tr><td>2.1</td><td>2.2</td><td>2.3</td></tr><tr><td>3.1</td><td>3.2</td><td>3.3</td></tr>
</table><!--iframe标签,在原页面之上显示一个小的页面其中的 name 属性可以作为超链接的 target 属性,点击超链接后将在 iframe 中显示-->
<iframe src="1.html" width="500" height="400" name="abc"></iframe>
<a href="2.html" target="abc"> 超链接 </a>

5 表单与表单的提交

表单类型单独列出,可以使用 table 实现对齐。

		<!-- 要顺利提交表单,需要为所有项加上 value 或者 name 属性 --><form action="http://localhost:8080" method="post">姓名:<input type="text" value="默认姓名"/></br>密码:<input type="password" value="default"/></br><!-- name 属性用于分组,同一组的选项互斥-->性别:<input type="radio" name="sex" checked="checked"/><input type="radio" name="sex"/></br>爱好:<input type="checkbox" checked="checked"/>跑步 <input type="checkbox"/>跳绳</br>国籍:<select><option>--请选择--</option><option selected="selected">CHN</option><option>USA</option></select><br/>简介:<textarea rows="10" cols="20">默认简介</textarea><br/>附件:<input type="file"/></br><input type="reset" value="重置"><input type="submit" value="提交"></form>

在这里插入图片描述

  • form 标签的 action 属性设置提交的服务器地址,method 属性设置提交的方式 GET(默认) 或 POST
  • GET 请求的特点是:
    1. 浏览器地址栏中的地址是:服务器地址 + ? + 请求参数(请求参数的格式是 name=value&name=value)
    2. 不安全
    3. 有数据长度的限制
  • POST 请求的特点:
    1. 浏览器地址栏中只有服务器地址(action的属性值)
    2. 相对于GET请求要安全
    3. 理论上没有数据长度的限制
  • 表单提交的时候,数据没有发送给服务器的三种情况:
    1. 表单项没有name属性值
    2. 单选 radio 、复选 checkbox、下拉列表中的 option 标签 都需要添加value属性,以便发送给服务器
    3. 表单项不在提交的form标签中

二 CSS

1 语法格式

/* 标签名选择器,样式绑定标签 */
label_name {  property1: val1;property2: val2;
}/* id选择器,样式绑定具体的id,id是人为设定的,每个实例不相同*/
#id {property1: val1;property2: val2;
}/* class选择器,样式绑定标签分配的class,可以多个实例绑定一个class */
.class class_name {property1: val1;property2: val2;
}/* 组合选择器,选择器间是并的关系 */
选择器1, 选择器2 ... {property1: val1;property2: val2;
}

2 使用方法

    <head>  <!-- HEAD --><meta charset="UTF-8"><title> my_title </title>/* 导入已经写好的CSS文件(推荐) */<link rel="stylesheet" type="text/CSS" href="mycss.css">/* 或者把CSS写到此处的 style 标签中 */<style type="text/css">label_name {  property1: val1;property2: val2;}</style></head>

三 JavaScript

1 概述

  • JS 运行在客户端,需要运行浏览器来解析执行 JavaScript 代码,和 Java 并无直接关系。
  • JS 是弱类型的语言,Java 是强类型的语言。强弱的差别在于定义变量后,变量的数据类型是否可变。
  • 特点是 交互性(信息的动态交互)、安全性(不允许直接访问本地硬盘)、跨平台性(只要是可以解释 JS 的浏览器都可以执行,和平台无关)。

2 与 HTML 结合的两种方式

  • 在 HTML 文件中的 head 部分,用 script 标签写入;
  • 在 script 标签中导入 JS 文件。

上述两种方法不能写在一个标签里。

<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">alert('JS嵌入方式1');</script><script src="myjs.js"></script> <!-- 文件内容: alert('JS嵌入方式2'); -->
</head>

3 变量类型及特殊值

关键字 对应类型
number数值类型
string字符串类型
object对象类型
bool布尔类型
function函数类型



特殊值 含义
undefined未定义,所有 JS 变量未赋于初始值的时候,默认值都是 undefined
null
NaN非数字非数值

4 关系、逻辑运算

  • ==比较两个变量的值是否相等(比如,“123”==123是成立的), ===比较两个变量的类型和值是否相等;
  • JS 中所有变量都可以作为布尔值使用,0、null、undefined、空串 都认为是 false;
  • ||(或) &&(与) 具有短路特性,返回值为第一个导致结果的变量

5 数组

  • 数组不会出现越界的问题。在超过原来长度的位置赋值时,会进行自动扩容(读操作不会扩容)。
// 数组定义
var arr = [1, "abc"];// 数组遍历
for (var i = 0; i < arr.length; i++) {alert(arr[i])
}// 自动扩容,下标2、3、4的元素均为undefined
arr[5] = 2;

6 函数

  • JS 不允许函数重载。一个函数名只能对应一个具体实现。
        function noParam() {alert('无参函数调用');}noParam();function withParam(a, b) {alert("有参函数调用" + a + b);}withParam(1, 2);function withReturn(a, b) {alert("有参有返回值函数调用");return a + b;}alert(withReturn(10, 5));
  • 隐形参数 arguments 将所有实参组织为一个数组,通过下标可以访问所有参数。
        function testInvisibleParams() {var res = 0;for (var i = 0; i < arguments.length; i++) {res += arguments[i];}return res;}alert(testInvisibleParams(1, 2, 3, 4));

7 事件

  • 常用事件
事件操作
onload(加载完成)常用做页面 JS 代码初始化操作
onclick(单击)按钮的点击响应操作
onblur(失去焦点)输入框失去焦点后验证其输入内容是否合法
onchange(内容发生改变)下拉列表和输入框内容发生改变后操作
onsubmit(表单提交)表单提交前,验证所有表单项是否合法
  • 事件需要进行注册才能使用:
    • 静态注册:通过 HTML 标签的事件属性,直接赋于事件响应后的代码;
    • 动态注册:先通过 JS 代码得到标签的 dom 对象,然后再通过 dom 对象.事件名 = function(){} 这种形式赋于事件响应后的代码。


  • onload 事件
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">function onloadEvent() {alert("静态注册onload事件,需要在body标签下添加 οnlοad='onloadEvent' ")}window.onload = function () {alert("动态注册onload事件")}</script>
</head>
<body></body>
</html>
  • onclick 事件
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">function onclickEvent() {alert("静态注册onclick事件")}window.onload = function () {<!-- document对象表示整个页面,通过id获取button对象 -->var btn2_obj = document.getElementById("btn2");<!-- 绑定行为 -->btn2_obj.onclick = function () {alert("动态注册onclick事件")}}</script>
</head>
<body><button onclick="onclickEvent()">静态注册的按钮</button><button id="btn2">动态注册的按钮</button>
</body>
</html>
  • onblur 事件(同上)
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">function onblurEvent() {console.log("静态失去焦点");}window.onload = function () {var pw = document.getElementById("p");pw.onblur = function () {console.log("动态失去焦点");}}</script>
</head>
<body>账户:<input type="text" onblur="onblurEvent()"/>密码:<input type="password" id="p"/>
</body>
</html>
  • onchange 事件,绑定的是 select 而非 option 标签
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">function onchangeEvent() {alert("静态注册onchange");}window.onload = function () {var select2 = document.getElementById("s");select2.onchange = function () {alert("动态注册onchange")}}</script>
</head>
<body>选择1:<select onchange="onchangeEvent()"><option>选项11</option><option>选项12</option></select>选择2:<select id="s"><option>选项21</option><option>选项22</option></select>
</body>
</html>
  • onsubmit 事件,绑定的是表格而非按钮,返回 false 则不会提交表单
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">function onsubmitEvent() {alert("静态注册onsubmit");<!--如果发现不合法,返回false,阻止提交-->return false;}window.onload = function () {var form2 = document.getElementById("f");form2.onsubmit = function () {alert("动态注册onsubmit");<!--如果发现不合法,返回false,阻止提交-->return false;}}</script>
</head>
<body><form action="http://localhost:8080" onsubmit="return onsubmitEvent()"> <!--静态注册 return 不能少--><input type="submit" value="静态注册提交"></form><form action="http://localhost:8080" id="f"><input type="submit" value="动态注册提交"></form>
</body>
</html>

8 DOM (Document Object Model)

  • 简单来说,将整个 HTML 文件视为一个 document 对象,并把其中所有的标签对象化,形成了树型结构。
  • document 实例提供查询方法,使用优先级从高到低:getElementByID(返回一个实例),getElementByName(可以数组形式返回多个实例),getElementByTagName(以数组形式返回指定标签的对象)。注意:页面加载完之后才能进行查询!不仅限于放在 onload 事件中。
  • document 实例提供创建方法:createElement
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">window.onload = function () {var new_div = document.createElement("div");new_div.innerHTML = "你好";document.body.appendChild(new_div);  <!-- 在加载完后执行 -->}</script>
</head>
<body></body>
</html>

在这里插入图片描述

9 DOM实例:验证用户名是否有效

限制用户名由数字和字母组成,长度区间为 [5, 12]

<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script>window.onload = function () {var tip = document.getElementById("tip");var btn = document.getElementById("btn");var text = document.getElementById("text");btn.onclick = function () {var input = text.value;var pattern = /^\w{5,12}$/;if (pattern.test(input)) {  <!-- 匹配正则表达式 -->tip.innerHTML = "通过";  <!-- innerHTML 返回的是开始和结束标签之间的值,可读写-->} else {tip.innerHTML = "不通过";}}}</script>
</head>
<body>
<input type="text" id="text">
<span id="tip" style="color: brown"></span>
<button id="btn">检查</button>
</body>
</html>

四 Tomcat

  • 简单来说,Tomcat 就是一个运行JAVA的网络服务器。
  • HTML 文件通过本地访问,使用的协议是 file,执行的操作是直接获取并解析;
  • IDEA 2021.3.1 创建JavaWeb工程的方法
  • 通过WEB服务器访问,使用的协议是 http,经过了客户端请求与服务器响应的过程,执行操作如下图:
    在这里插入图片描述

五 Servlet

1 举例:向数据库中添加表单信息

在这里插入图片描述

  1. 客户端请求表单页面 add.html(表单指定 action=“add”(可以自定义) method=“post”),服务器返回。
  2. 客户端填写表单,使用 HttpRequest 实例提交给服务器。
  3. 服务器的具有一个类 ,继承自 HttpServlet 类,其中的 doPost() 方法定义了 post 请求的处理与返回过程,调用 DAO 将表单信息写入数据库。
//@WebServlet("/add")
public class AddServlet extends HttpServlet {@Overridepublic void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// method=post 设置编码方式防止乱码,且在获取参数的操作之前(放在首行)request.setCharacterEncoding("UTF-8");String name = request.getParameter("name");System.out.println(name);// 调用DAO// ...}
}
  1. 如何指定 action=“add” 与自定义类 AddServlet 的绑定?
    一种方式是使用 web.xml 配置(另一种是通过在 AddServlet 注释 @WebServlet(“/add”) ):
	<!--指定servlet信息--><servlet><servlet-name>AddServlet</servlet-name><servlet-class>com.atguigu.servlets.AddServlet</servlet-class></servlet><!--设定servlet映射--><servlet-mapping><servlet-name>AddServlet</servlet-name><url-pattern>/add</url-pattern>  <!--action="add"--></servlet-mapping>

2 Servlet 的继承关系

  • 继承关系: HttpServlet 具体实现类 -> GenericServlet 抽象类 -> Servlet 接口
  • Servlet中的核心方法:service()
  • 当收到请求,service 方法会自动响应(tomcat 容器调用),在 HttpServlet 中分析请求的方式:到底是get、post、head 等等,然后再决定调用具体的 doXX 的方法
  • 在 HttpServlet 中,doXX 方法默认都是405(报错信息是找不到方法实现),除非子类去实现对应的 doXX 方法,否则默认会报405错误。

3 Servlet 的生命周期

  • 三个重要的方法:init、service、destory
  • 默认情况下, 第一次接收请求时,Servlet 会进行实例化(调用构造方法)、初始化(调用init())、然后服务(调用service());从第二次请求开始,每一次都是服务(调用service());当容器关闭时,其中的所有的 Servlet 实例会被销毁(调用destroy())。
  • 如果需要提高响应速度,应该设置 Servlet 的初始化时机,在第一次请求之前执行实例化和初始化。具体做法是,在 web.xml 中的 <servlet> 中添加 <load-on-startup> 标签。
  • Servlet 是单例的、线程不安全的。单例是指,对于一个确定的 Servlet 类型,所有的请求都是同一个 Servlet 实例去响应;由于 Servlet 线程不安全,所以尽量避免在其中设置成员变量,如果设置尽量不要读写。

4 HTTP 协议与 Session会话跟踪

  • HTTP 协议是无状态的,需要通过会话跟踪技术保存用户的历史信息。
  • HTTP 请求与响应报文的格式略。
  • 常用的API:
    request.getSession() -> 获取当前的会话,没有则创建一个新的会话
    request.getSession(true) -> 效果和不带参数相同
    request.getSession(false) -> 获取当前会话,没有则返回null,不会创建新的
    session.getId() -> 获取sessionID
    session.isNew() -> 判断当前session是否是新的
    session.getMaxInactiveInterval() -> session的非激活间隔时长,默认1800秒
    session.setMaxInactiveInterval()
    session.invalidate() -> 强制让会话立即失效

5 服务器端内部转发、重定向

  • 服务器端内部转发对客户端是不可见的,执行方法:request.getRequestDispatcher("...").forward(request, response)
    在这里插入图片描述

  • 重定向对客户端可见,并且会显示地更改 URL,执行方法:response.sendRedirect("...")
    在这里插入图片描述

6 Servlet 保存作用域

  1. request:一次请求响应内有效。
  2. session:一次会话内有效。
  3. application:一次应用内有效,除非关闭服务器。
public class Demo extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// request 级别req.setAttribute("property1", 1);// session 级别HttpSession session = req.getSession();session.setAttribute("property2", 2);// application 级别ServletContext servletContext = req.getServletContext();servletContext.setAttribute("property3", 3);}
}

7 Servlet 的 init 方法与初始化参数设置

  • 两种 init 方法:
    如果需要进行一些初始化操作,重写无参的 init 方法
	// Servlet中的初始化方法有两个:init() , init(config)// 其中带参数的方法代码如下:public void init(ServletConfig config) throws ServletException {this.config = config ;init();  // *调用无参的init*}// 另外一个无参的init方法如下:public void init() throws ServletException{}
  • 初始化参数设置
1. 通过 web.xml 配置<servlet><servlet-name>Demo01Servlet</servlet-name><servlet-class>com.atguigu.servlet.Demo01Servlet</servlet-class><!--设置参数--><init-param><param-name>hello</param-name><param-value>world</param-value></init-param></servlet>2. 通过注解
@Webservlet(urlPatterns = {"/demo01"} ,initParams = {@WebInitParam(name="hello",value="world")})
  • 读取初始化参数:
ServletConfig config = getServletConfig();  // 获取config对象
config.getInitParameter("hello");  // 读取初始化的值

8 ServletContext

  • ServletContext是一个全局的储存信息的空间,服务器开始就存在,服务器关闭才释放(application级别)
  • 类似 session,可以想象成一个 map
  • 多个Servlet可以通过ServletContext对象来实现数据间的共享,如果是涉及到不同用户共享数据,而这些数据量不大,同时又不希望写入数据库中,我们就可以考虑使用 ServletContext 实现
  • 初始化 ServletContext 时,不能写在具体的某个 servlet 标签中,因为它是全局的
<!--写在servlet之外-->
<context-param><param-name>name</param-name><param-value>gavin</param-value>
</context-param><servlet>  <servlet-name>MyServlet</servlet-name>  <servlet-class>com.gavin.servlet.MyServlet</servlet-class>  <init-param>  <param-name>encoding</param-name>  <param-value>utf-8</param-value>  </init-param>  
</servlet>  

六 Thymeleaf

1 配置过程

  1. 添加依赖, maven 中添加:
        <dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf</artifactId><version>3.0.14.RELEASE</version></dependency>
  1. 新建一个类 ViewBaseServlet 继承 HttpServlet
public class ViewBaseServlet extends HttpServlet {private TemplateEngine templateEngine;@Overridepublic void init() throws ServletException {// 1.获取ServletContext对象ServletContext servletContext = this.getServletContext();// 2.创建Thymeleaf解析器对象ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);// 3.给解析器对象设置参数// ①HTML是默认模式,明确设置是为了代码更容易理解templateResolver.setTemplateMode(TemplateMode.HTML);// ②设置前缀String viewPrefix = servletContext.getInitParameter("view-prefix");templateResolver.setPrefix(viewPrefix);// ③设置后缀String viewSuffix = servletContext.getInitParameter("view-suffix");templateResolver.setSuffix(viewSuffix);// ④设置缓存过期时间(毫秒)templateResolver.setCacheTTLMs(60000L);// ⑤设置是否缓存templateResolver.setCacheable(true);// ⑥设置服务器端编码方式templateResolver.setCharacterEncoding("utf-8");// 4.创建模板引擎对象templateEngine = new TemplateEngine();// 5.给模板引擎对象设置模板解析器templateEngine.setTemplateResolver(templateResolver);}protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {// 1.设置响应体内容类型和字符集resp.setContentType("text/html;charset=UTF-8");// 2.创建WebContext对象WebContext webContext = new WebContext(req, resp, getServletContext());// 3.处理模板数据templateEngine.process(templateName, webContext, resp.getWriter());}
}
  1. 在 web.xml 配置前缀和后缀,根据逻辑视图名称得到物理视图名称。
    逻辑视图名称 : index
    物理视图名称 : view-prefix + 逻辑视图名称 + view-suffix
    真实的视图名称: / index .html
    <context-param><param-name>view-prefix</param-name><param-value>/</param-value></context-param><context-param><param-name>view-suffix</param-name><param-value>.html</param-value></context-param>
  1. 创建自定义的 Servlet 类,继承 ViewBaseServlet,调用 super.processTemplate("index",request,response); 定位到指定 HTML 页面。
  2. 对于跳转到的 HTML 页面,需要显示查询内容。设置 <html lang="en" xmlns:th="http://www.thymeleaf.org">,使用 thymeleaf 的标签完成操作。

2 Servlet 优化 - 合并同类方法

  • 之前的一个 Servlet 只提供一种方法,此处的改进是将同类的多种方法合并到一个 Servlet 中
  • 使用反射代替 switch-case
@WebServlet("/fruit.do")
public class FruitServlet extends ViewBaseServlet {private final FruitDAO fruitDAO = new FruitDAOImpl();/*** 设置一个Fruit 的 meta servlet*/@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {req.setCharacterEncoding("UTF-8");String operation = (String) req.getAttribute("operation");// 简化了switch-caseMethod[] methods = this.getClass().getDeclaredMethods();for (Method method: methods) {method.setAccessible(true);if (operation.equals(method.getName())) {try {method.invoke(this, req, resp);return ;} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}throw new IOException("输入操作错误");  // 对应default}private void insertFruit(HttpServletRequest request, HttpServletResponse response) {// ...}private void selectFruit(HttpServletRequest request, HttpServletResponse response) {// ...}
}

3 Servlet 优化 - dispatchedServlet

在这里插入图片描述

  • 相当于一个 meta 的 Servlet,称为 DispatchedServlet,继承自 ViewBaseServlet。合并所有种类的 Servlet,并将原来的 Servlet 转为 Controller,剥夺其注释 @WebServlet
  • 在 src 目录下创建 applicationContext.xml,利用 bean 标签,为参数名和 Controller 建立映射
  • DispatchedServlet 的 init 方法根据 xml 配置 Map<String,Object> beanMap
<?xml version="1.0" encoding="utf-8"?><beans><!-- 这个bean标签的作用是 将来servletpath中涉及的名字对应的是fruit,那么就要FruitController这个类来处理 --><bean id="fruit" class="com.atguigu.fruit.controllers.FruitController"/>
</beans>
  • 使用时,向 DispatchedServlet 传递参数,由其 service 方法负责解析,并根据 beanMap 调用指定的 Controller,具体步骤:
    • 获取参数:获取即将要调用的方法的参数签名信息
    • 执行方法:Object returnObj = method.invoke(controllerBean , parameterValues);
    • 视图处理:根据返回值调用重定向等 String returnStr = (String)returnObj; if(returnStr.startWith("redirect:")){ .... } else if.....

七 MVC

在这里插入图片描述

1 概念

  • MVC(Model–View–Controller)模式是软件工程中的一种软件架构模式,它把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
  • Controller 作为 Model 和 View 部分的“胶水”,本身不适合包含太多的逻辑。

2 降低各层间的耦合 - IOC 与 DI

  • DI(Dependency Injection,依赖注入)是 IOC(Inversion of Control,控制反转)最常用的方法。
  • IOC 是一种设计思想,核心是,将设计好的对象交给容器控制,而不是传统的在对象内部直接控制。 把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散的耦合。
  • Spring 所倡导的开发方式就是如此,所有的类都会在 spring 容器中登记,告诉 spring 你是个什么东西,你需要什么东西,然后 spring 会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring 容器来控制,也就是说控制对象生存周期的不再是引用它的对象,而是 spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被 spring 控制,所以这叫控制反转。
  • IOC 容器实际上就是 map(key,value),里面存的是各种对象(在 xml 里配置的 bean 节点、service、controller、component),在项目启动的时候会读取配置文件里面的 bean 节点,根据全限定类名使用反射创建对象并放到 map 里。

在这里插入图片描述
通过 IOC 容器,上述过程转为:
在这里插入图片描述

  • IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过 DI 来实现的。在类中需要使用到的对象,全部通过反射从第三方容器注入而不是自己创建
  • 比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个 Connection 对象,有了 spring 只需要告诉 spring ,A中需要一个 Connection,至于这个 Connection 怎么构造,何时构造,A不需要知道。在系统运行时,spring 会在适当的时候制造一个 Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection 才能正常运行,而这个 Connection 是由 spring 注入到A中的,依赖注入的名字就这么来的。

3 IOC 与 DI 的实现过程

  1. 对于 Servlet - Controller - Service - DAO 的结构,首先将用到的类,及其依赖关系,注册到 applicationContext.xml 中。
<?xml version="1.0" encoding="utf-8"?><beans><!-- FruitDAO不依赖于其它组件 --><bean id="fruitDAO" class="com.atguigu.fruit.dao.impl.FruitDAOImpl"/><!-- FruitService依赖于FruitDAO(FruitService类包含FruitDAO属性) --><bean id="fruitService" class="com.atguigu.fruit.service.impl.FruitServiceImpl"><!-- property标签用来表示属性;name表示属性名;ref表示引用其他bean的id值--><property name="fruitDAO" ref="fruitDAO"/></bean><!-- FruitController依赖于FruitService(FruitController类包含FruitService属性) --><bean id="fruit" class="com.atguigu.fruit.controllers.FruitController"><property name="fruitService" ref="fruitService"/></bean><!-- FruitServlet中具有 包含所有对象的 map,以BeanFactory作为 map 的包装 -->
</beans>
  1. 使用 BeanFactory 读取 xml 配置,填充 map,并设置依赖关系(比如 A 以 B 作为属性,执行此过程前将属性值设置为 null,在此过程将 A 的对应属性设置为 B 的实例,完成依赖注入)

BeanFactory 实现:

public class ClassPathXmlApplicationContext implements BeanFactory {private Map<String,Object> beanMap = new HashMap<>();public ClassPathXmlApplicationContext(){try {InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");//1.创建DocumentBuilderFactoryDocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();//2.创建DocumentBuilder对象DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;//3.创建Document对象Document document = documentBuilder.parse(inputStream);//4.获取所有的bean节点NodeList beanNodeList = document.getElementsByTagName("bean");for(int i = 0 ; i<beanNodeList.getLength() ; i++){Node beanNode = beanNodeList.item(i);if(beanNode.getNodeType() == Node.ELEMENT_NODE){Element beanElement = (Element)beanNode ;String beanId =  beanElement.getAttribute("id");String className = beanElement.getAttribute("class");Class beanClass = Class.forName(className);//创建bean实例Object beanObj = beanClass.newInstance() ;//将bean实例对象保存到map容器中beanMap.put(beanId , beanObj) ;//到目前为止,此处需要注意的是,bean和bean之间的依赖关系还没有设置}}//5.组装bean之间的依赖关系for(int i = 0 ; i<beanNodeList.getLength() ; i++){Node beanNode = beanNodeList.item(i);if(beanNode.getNodeType() == Node.ELEMENT_NODE) {Element beanElement = (Element) beanNode;String beanId = beanElement.getAttribute("id");NodeList beanChildNodeList = beanElement.getChildNodes();for (int j = 0; j < beanChildNodeList.getLength() ; j++) {Node beanChildNode = beanChildNodeList.item(j);if(beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){Element propertyElement = (Element) beanChildNode;String propertyName = propertyElement.getAttribute("name");String propertyRef = propertyElement.getAttribute("ref");//1) 找到propertyRef对应的实例Object refObj = beanMap.get(propertyRef);//2) 将refObj设置到当前bean对应的实例的property属性上去Object beanObj = beanMap.get(beanId);Class beanClazz = beanObj.getClass();Field propertyField = beanClazz.getDeclaredField(propertyName);propertyField.setAccessible(true);propertyField.set(beanObj,refObj);}}}}} catch (ParserConfigurationException e) {e.printStackTrace();} catch (SAXException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();}}@Overridepublic Object getBean(String id) {return beanMap.get(id);}
}
  1. 重写 Servlet 的 无参 init 方法和 service 方法。其中 init 方法负责获取 BeanMap,service 方法负责解析方法调用,执行方法调用,处理返回值。
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet{private BeanFactory beanFactory ;public DispatcherServlet(){}public void init() throws ServletException {super.init();beanFactory = new ClassPathXmlApplicationContext();}@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//设置编码request.setCharacterEncoding("UTF-8");//假设url是:  http://localhost:8080/pro15/hello.do//那么servletPath是:    /hello.do// 我的思路是:// 第1步: /hello.do ->   hello   或者  /fruit.do  -> fruit// 第2步: hello -> HelloController 或者 fruit -> FruitControllerString servletPath = request.getServletPath();servletPath = servletPath.substring(1);int lastDotIndex = servletPath.lastIndexOf(".do") ;servletPath = servletPath.substring(0,lastDotIndex);Object controllerBeanObj = beanFactory.getBean(servletPath);String operate = request.getParameter("operate");if(StringUtil.isEmpty(operate)){operate = "index" ;}try {Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();for(Method method : methods){if(operate.equals(method.getName())){//1.统一获取请求参数//1-1.获取当前方法的参数,返回参数数组Parameter[] parameters = method.getParameters();//1-2.parameterValues 用来承载参数的值Object[] parameterValues = new Object[parameters.length];for (int i = 0; i < parameters.length; i++) {Parameter parameter = parameters[i];String parameterName = parameter.getName() ;//如果参数名是request,response,session 那么就不是通过请求中获取参数的方式了if("request".equals(parameterName)){parameterValues[i] = request ;}else if("response".equals(parameterName)){parameterValues[i] = response ;}else if("session".equals(parameterName)){parameterValues[i] = request.getSession() ;}else{//从请求中获取参数值String parameterValue = request.getParameter(parameterName);String typeName = parameter.getType().getName();Object parameterObj = parameterValue ;if(parameterObj!=null) {if ("java.lang.Integer".equals(typeName)) {parameterObj = Integer.parseInt(parameterValue);}}parameterValues[i] = parameterObj ;}}//2.controller组件中的方法调用method.setAccessible(true);Object returnObj = method.invoke(controllerBeanObj,parameterValues);//3.视图处理String methodReturnStr = (String)returnObj ;if(methodReturnStr.startsWith("redirect:")){        //比如:  redirect:fruit.doString redirectStr = methodReturnStr.substring("redirect:".length());response.sendRedirect(redirectStr);}else{super.processTemplate(methodReturnStr,request,response);    // 比如:  "edit"}}}} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}
}

八 Filter

1 概述

  • 继承自 Filter 类,具有 init, doFilter, destory 方法
  • 可以使用注解的形式 @WebFilter("fruit.do"),也可以在 web.xml 中配置
  • 使用注解形式,当具有多个 Filter 时,按照类名的字典序组织过滤顺序
    在这里插入图片描述
@WebFilter("*.do")
public class Demo01Filter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("before");//放行filterChain.doFilter(servletRequest,servletResponse);System.out.println("after");}@Overridepublic void destroy() {}
}

2 使用 Filter 实现事务的原子性

在这里插入图片描述

  • 利用 Filter 的机制,在放行之前撤销 conn 的自动提交,在返回时手动执行提交,并在捕获到异常时执行回滚
  • 要求事务执行的过程中,遇到的异常要层层向外抛出,直到被 Filter 捕获,而不是就地解决
  • conn 绑定 ThreadLocal 实例,再进一步保存到 ThreadLocalMap 中,保证了多个 DAO 共用同一个数据库连接,不会因为连接的关闭而自动提交,破坏事务的原子性

九 Listener

  • 监听某个组件的某种行为,当这种行为被监听到时,调用指定的方法
  • 可以用于完成初始化的创建,以及结束时的销毁操作
  • 一个应用实例:IOC 容器的 beanMap,当监听到 ServletContext 对象创建时,在监听器内进行初始化,而非在 Servletinit 方法中完成
// 监听上下文启动,在上下文启动的时候去创建IOC容器,然后将其保存到 application 作用域
// 后面DispatchedServlet 再从 application 作用域中去获取IOC容器@WebListener
public class ContextLoaderListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {//1.获取ServletContext对象ServletContext application = servletContextEvent.getServletContext();//2.获取上下文的初始化参数(bean类型以及依赖关系)String path = application.getInitParameter("contextConfigLocation");//3.创建IOC容器BeanFactory beanFactory = new ClassPathXmlApplicationContext(path);//4.将IOC容器保存到application作用域application.setAttribute("beanFactory", beanFactory);}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {// ...}
}

十 总结

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307163.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

心想技术驱动业务,却在背道而驰

这里是Z哥的个人公众号每周五11&#xff1a;45 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「165」篇原创敬上大家好&#xff0c;我是Z哥。相信每一位真正的程序员心里都有这样一个念想&#xff1a;只要我的技术够牛&#xff0c;就能驱动业务的发展。但是往…

后端学习 - SpringMVC

文章目录一 SpringMVC 简介1 MVC2 SpringMVC3 创建第一个 SpringMVC 项目二 RequestMapping1 注解类与方法的区别2 value 属性3 method 属性4 params 属性5 headers 属性6 SpringMVC 支持路径中的占位符三 获取 Request 的一系列参数1 通过控制器方法的形参2 控制器方法形参 映…

hbase shell远程连接_hbase与phoenix集成

Phoenix是构建在HBase之上的关系型数据库层&#xff0c;作为内嵌的客户端JDBC驱动用以对HBase中的数据进行低延迟访问Phoenix会将用户编写的sql查询编译为一系列的scan操作&#xff0c;最终产生通用的JDBC结果集返回给客户端Phoenix可以看成是mysql准备安装包apache-phoenix-4.…

对精致码农大佬的 [理解 volatile 关键字] 文章结论的思考和寻找真相

一&#xff1a;背景1. 讲故事昨天在园里的编辑头条看到 精致码农大佬 写的一篇题为&#xff1a;[C#.NET 拾遗补漏]10&#xff1a;理解 volatile 关键字 (https://www.cnblogs.com/willick/p/13889006.html) 的文章&#xff0c;大概就是说在 多线程环境下&#xff0c;一个在debu…

后端学习 - SpringBoot

SpringBoot 是整合 Spring 技术栈的一站式框架&#xff0c;是简化 Spring 技术栈的快速开发脚手架约定大于配置 文章目录一 概述1 第一个 SpringBoot 项目2 SpringBoot 特性&#xff1a;依赖管理3 SpringBoot 特性&#xff1a;自动配置二 SpringBoot 的 IOC容器1 组件添加&…

centos rpm 安装 perl_Linux【常用软件安装篇】

摘要&#xff1a;本文介绍Linux常用的软件安装方式以及jdk、vim、mysql、tomcat、redis的安装过程。1 Linux常用软件安装方式常用方式有&#xff1a;rmp包安装、yum指令安装、源码包安装、解压免安装。1.1 rpm包安装rpm是Red-Hat Package Manager&#xff08;RPM软件包管理器&a…

日计不足涓滴成河-自定义响应结果格式化器

什么是响应结果响应结果就是&#xff0c;在客户端向服务器发出请求后&#xff0c;服务器根据客户端的请求参数&#xff0c;给出的结果&#xff0c;这就是一个完整的响应结果过程。响应的结果包含的内容非常多&#xff0c;主要的有 HTTP Status Code&#xff0c;Content-Type,Co…

docker 容器启动顺序_Docker容器启动时初始化Mysql数据库

1. 前言 Docker在开发中使用的越来越多了&#xff0c;最近搞了一个Spring Boot应用&#xff0c;为了方便部署将Mysql也放在Docker中运行。那么怎么初始化 SQL脚本以及数据呢&#xff1f; 我这里有两个传统方案。 第一种方案是在容器启动后手动导入&#xff0c;太low了不行。第二…

后端学习 - JVM(上)内存与垃圾回收

JVM 架构图 文章目录一 JVM 简介二 类加载子系统&#xff1a;1 作用2 类的三个加载过程3 类加载器的分类4 双亲委派机制 & Tomcat为何不遵循5 两个 class 对象为同一个类的必要条件三 运行时数据区&#xff1a;PC寄存器&#xff08;Program Counter Register&#xff09;四…

SM2 国密算法被 Linux 内核社区接受

喜欢就关注我们吧&#xff01;10 月 25 日&#xff0c;有开发者发文称&#xff0c;SM2 国密算法终于被 Linux 内核社区接受了。该作者表示&#xff0c;SM2 的补丁已经更新到了 v7 版本&#xff0c;这个版本的补丁最终被社区接受&#xff0c;目前已经合并到了 Linux 主线的 5.10…

后端学习 - MyBatis

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的 持久层框架 文章目录一 基于配置文件的 MyBatis 搭建1 搭建过程&#xff08;增删改&#xff09;2 查询操作3 特殊操作二 MyBatis 获取参数值的方式1 单个字面量类型的参数2 多个字面量类型的参数3 Map 类型的参数4 实体…

国产操作系统发展离不开人才和市场

日前&#xff0c;中国 1024 程序员节盛大举行&#xff0c;一大批开源大咖齐聚千年岳麓&#xff0c;围绕开源标准、生态、人才发展等主题分享&#xff0c;共议开源软件与操作系统未来。其中&#xff0c;统信软件总经理刘闻欢表示&#xff0c;“有了市场才会被真正的用起来”&…

后端学习 - Redis

文章目录一 Redis 概述Redis 为什么是单线程&#xff0c;单线程为什么这么快&#xff1f;数据存储结构二 常用数据类型1 String2 HashHash 的扩容机制&#xff1a;渐进式 rehash*3 List4 Set5 Zset三 Redis 事务1 乐观锁与 watch 命令2 事务的三个特性四 Redis 持久化1 RDB(Red…

再被补刀!Flash又遭抛弃,你会怀念它吗?

喜欢就关注我们吧&#xff01;微软近日发布通知&#xff0c;称更新了关于 Adobe Flash Player 的删除。微软更新目录站点可下载更新 KB4577586&#xff0c;用于删除 Flash Player。此更新适用于所有受支持的操作系统版本。重要版本 Windows 10 和 Windows 8.1 的可选更新也将在…

4位加法器的设计代码verilog_HDLBits:在线学习Verilog(六 · Problem 25-29)

本系列文章将和读者一起巡礼数字逻辑在线学习网站 HDLBits 的教程与习题&#xff0c;并附上解答和一些作者个人的理解&#xff0c;相信无论是想 7 分钟精通 Verilog&#xff0c;还是对 Verilog 和数电知识查漏补缺的同学&#xff0c;都能从中有所收获。附上传送门&#xff1a;M…

译 | 将数据从Cosmos DB迁移到本地JSON文件

点击上方蓝字关注“汪宇杰博客”原文&#xff1a;Azure Tips and Tricks翻译&#xff1a;汪宇杰在Cosmos DB中使用数据迁移工具有一项重复的任务是将数据从一种数据库格式迁移到另一种数据库格式。我最近使用Cosmos DB作为数据库来存储Ignite大会发出的所有推文。然而一旦获得了…

在线教育后端开发项目总结

文章目录一 数据库访问接口1 MyBatis2 Spring Data JPA3 Spring Data MongoDB二 数据库1 MySQL2 MongoDB3 Redis三 开发规范化、响应格式与异常处理1 开发规范2 响应格式3 异常处理四 RabbitMQ五 Spring Cloud 相关工具1 Eureka2 Ribbon3 Feign4 Zuul 网关六 搜索服务1 Elastic…

通讯故障_掌握PLC必备知识,人机界面和 PLC 出现通讯故障如何分析解决

此次主要在阐述人机界面和 PLC 通讯时的模式状态&#xff0c;并列举了通讯故障实例。帮助大伙加深对这俩者的了解&#xff0c;掌握起来也不再是难题&#xff0c;解决掉拦路虎。一 台数 显 四 辊 卷 板 机PLC 控 制 系 统 核 心 与 人机界面在使用过程中&#xff0c;出现人机界面…

后端学习 - 设计模式与设计原则

文章目录设计原则1 单一职责原则2 开闭原则3 Liskov 替换原则4 依赖倒置原则5 接口隔离原则6 迪米特法则设计模式&#xff1a;创建型模式1 工厂模式2 抽象工厂模式3 单例模式设计模式&#xff1a;行为型模式1 观察者模式2 模板模式3 备忘录模式设计模式&#xff1a;结构型模式1…

ai的预览模式切换_AI字体制作,用AI制作创意阶梯式文字

本篇教程通过AI制作一款创意阶梯式文字&#xff0c;教程中有很多知识点需要掌握&#xff0c;比如路径分割为网络&#xff0c;3D效果应用等&#xff0c;我们要利用他们创造出我们需要的文字出来&#xff0c;具体是如何制作的&#xff0c;我们通过教程一起来学习一下吧。效果图&a…