HTML
HTML介绍
名词解释:
HTML是Hyper Text Markup Language的缩写。意思是『超文本标记语言』
HTML结构
<html>
<head>
<title>这是我的第一个网页</title>
<meta charset="UTF-8">
</head>
<body>
HELLO WORLD!
</body>
</html>
①文档类型声明
HTML文件中第一行的内容,用来告诉浏览器当前HTML文档的基本信息,其中最重要的就是当前HTML文档遵循的语法标准。这里我们只需要知道HTML有4和5这两个大的版本,HTML4版本的文档类型声明是
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
HTML5版本的文档类型声明是:
<!DOCTYPE html>
②根标签
html标签是整个文档的根标签,所有其他标签都必须放在html标签里面。
<html></html>
④主体
body标签定义网页的主体内容,在浏览器窗口内显示的内容都定义到body标签内。
⑤注释
HTML注释的写法是:
<!-- 注释内容 -->
HTML语法规则
- 根标签有且只能有一个
- 无论是双标签还是单标签都必须正确关闭
- 标签可以嵌套但不能交叉嵌套
- 注释不能嵌套
- 属性必须有值,值必须加引号,单引号或双引号均可
- 标签名不区分大小写但建议使用小写
HTML标签
标题标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是一级标题</h1>
<h2>这是二级标题</h2>
<h3>这是三级标题</h3>
<h4>这是四级标题</h4>
<h5>这是五级标题</h5>
<h6>这是六级标题</h6>
</body>
</html>
页面效果展示
超链接标签
<a href="page02-anchor-target.html">点我跳转到下一个页面</a>
-
href 连接的地址
-
target:
self:在本窗口打开
blank:在一个新窗口打开
parent:在父窗口打开
top:在顶层窗口打开
换行标签
<br/>
比段落标签换行的两行间隔小
图片标签
<img src="/aaa/pro01-HTML/./images/mi.jpg" />
- src属性用来指定图片文件的路径
- width和height表示图片的大小
- alt表示图片的提示
列表标签
有序列表
武林高手排行榜
<body>
<ol>
<li>扫地僧</li>
<li>萧远山</li>
<li>慕容博</li>
<li>虚竹</li>
<li></li>
</body>
武林高手排行榜
- 扫地僧
- 萧远山
- 慕容博
- 虚竹
无序列表
<body>
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Grape</li>
</ul>
</body>
- Apple
- Banana
- Grape
块标签
块并不是为了显示文章内容的,而是为了方便结合CSS对页面进行布局。块有两种,div是前后有换行的块,span是前后没有换行的块。
<div style="border: 1px solid black;width: 100px;height: 100px;">This is a div block</div>
<span style="border: 1px solid black;width: 100px;height: 100px;">This is a span block</span>
HTML中的实体标签
在HTML文件中,<、>等等这样的符号已经被赋予了特定含义,不会作为符号本身显示到页面上,此时如果我们想使用符号本身怎么办呢?那就是使用HTML实体来转义。
表格标签
<html>
<head>
<title>表格标签的学习</title>
<meta charset="UTF-8">
</head>
<body>
<table border="1" width="600" cellspacing="0" cellpadding="4">
<tr align="center">
<th>姓名</th>
<th>门派</th>
<th>成名绝技</th>
<th>内功值</th>
</tr>
<tr align="center">
<td>乔峰</td>
<td>丐帮</td>
<td>少林长拳</td>
<td>5000</td>
</tr>
<tr align="center">
<td>虚竹</td>
<td>少林寺</td>
<td>七十二绝技</td>
<td>3000</td>
</tr>
</table>
</body>
- 表格 table
- 行 tr
- 列 td
- 表头列th
table中有如下属性(虽然淘汰)
- border:表格边框的粗细
- width:表格的宽度
- cellspacing:单元格间距
- cellpadding:单元格内填充
tr中有一个属性:align:center,left,right
td属性:
rowspan:合并行(跨几行合并)
colspan:合并列(跨几列合并)
表单标签
<html>
<head>
<title>表单标签的学习</title>
<meta charset="UTF-8">
</head>
<body>
<form action="demo02.html" method="post">
昵称:<input type="text" name="nickName" value="请输入用户名"/><br/>
密码:<input type="password" name="pwd"/><br/>
性别:<input type="radio" name="gender" value="male" checked="checked"/>男
<input type="radio" name="gender" value="female"/>女<br/>
爱好:<input type="checkbox" name="hobby" value="basketball"/>篮球
<input type="checkbox" name="hobby" value="football"/>足球
<input type="checkbox" name="hobby" value="earth"/>地球<br/>
星座:<select name="star">
<option value="1">白羊座</option>
<option value="2" selected="selected">天枰座</option>
<option value="3">金牛座</option>
<option value="4">双鱼座</option>
<option value="5">水瓶座</option>
</select><br/>
备注:<textarea name="remark" row="4" cols="5"></textarea><br/>
<input type="submit" value="注册"/>
<input type="reset" value="重置"/>
<input type="button" value="这是一个普通按钮"/>
</form>
</body>
frameset和iframe(淘汰)
<html>
<head>
<title>frameset学习</title>
<meta charset="UTF-8">
</head>
<!-- 一个页面分割成上下两行,上面占百分之二十的行长,下面百分之八十 -->
<frameset rows="20%,*">
<frame src="frames/top/.html"/>
<frameset cols="15%,*">
<frame src="frames/left.html"/>
<frameset rows="80%,*">
<frame src="frames/main.html"/>
<frame src="frams/bottom.html"/>
</frameset>
</frameset>
</frameset>
</html>
在一个页面嵌入一个子页面可以用iframe
<html>
<head>
<title>iframe学习</title>
<meta charset="UTF-8">
</head>
<body>
这里是demo06页面的内容!!
<iframe src="frames/top.html"/>
</body>
</html>
CSS
CSS的语法
<html>
<head>
<meta charset="UTF-8">
<!-- 内部样式 -->
<style type="text/css">
/* 标签样式 */
p {
color: red;
}
/* 类样式 */
.f20{
font-size: 20px;
}
/* id样式 */
#p4{
background-color: pink;
font-size: 24px;
font-weight: bolder;
font-style: italic;
font-family: "华文彩云";
}
/* 组合样式 */
div p{
color:blue;
}
div .f32{
font-size: 32px;
font-family: "黑体";
}
</style>
</head>
<body>
<p>这是段落一</p>
<p>这是段落二</p>
<p class="f20">这是段落三</p>
<!-- id属性尽量唯一 -->
<p id="p4">这是段落四</p>
<div>
<p><span>Hello</span></p>
<span class="f32">World</span>
<p class="f32">!!!</p>
</div>
<!-- 嵌入样式表 -->
<p style="border: ;"></p>
</body>
</html>
CSS最基本的分类:标签样式表,类样式表,ID样式表,组合样式表
CSS从位置上的分类:内部样式表(style在本页面head标签内部),嵌入样式表(syle在某个标签属性上),外部样式表(单独一个文件写css,通过引入该页面)
外部样式表的引入
<link rel="stylesheet" href="css文件地址">
CSS盒子模型(div)
<html>
<head>
<meta charset="UTF-8">
<!-- 内部样式 -->
<style type="text/css">
#div1{
width: 400px;
height: 400px;
background-color: greenyellow;
/* 边框样式 */
border-width: 4px; /* 边框粗细 */
border-style: solid; /* 边框样式 */
border-color: blue;/* 边框颜色 */
/*
border: 4px solid blue;
border-top: 4px solid blue; */
}
#div2{
width: 200px;
height: 200px;
background-color: darkorange;
/* margin-top: 100px;
margin-left: 100px; */
/* 外部填充 第一个上下,第二个左右*/
margin: 100px 100px;
padding-left: 50px;
padding-top: 50px;
}
#div3{
width: 100px;
height: 100px;
background-color: aquamarine;
}
</style>
</head>
<body>
<!--  空格 -->
<div id="div1">
<div id="div2">
<div id="div3"> </div>
</div>
</div>
</body>
</html>
CSS布局
position:absolute -->绝对定位,需要配合left,top
relative -->相对定位,一般和float,magin,padding…配合使用
JavaScript
定义:客户端的一个脚本语言
WEB
Tomcat
CS和BS区别
CS:客户端服务器架构(lol)
优点:充分利用客户端机器的资源,减轻服务器的负荷(一部分安全要求不高的计算任务存放在客户端执行,不需要把所有的计算和存储都在服务器端执行,从而减轻服务器的压力,也能够减轻网络负荷)
缺点:需要安装;升级维护成本较高
BS:浏览器服务器架构模式
优点:客户端不需要安装;维护成本较低。
缺点:所有的计算和存储任务都在服务端的,服务端的负荷较重;在服务端计算完成之后把结果在传输给客户端,客户端和服务器端会进行频繁的数据通信。从而网络负荷较重。
参考https://heavy_code_industry.gitee.io/code_heavy_industry/pro001-javaweb/lecture/
###Tomcat部署和启动
在tomcat的webapps目录下部署项目
启动:在tomcat的bin目录点击start
访问部署好的web资源:浏览器输入http://ip地址:8080/web项目名/资源名
IDEA部署Tomcat项目
1,创建artifacts(webapp目录下的web工程)
artifacts是部署包(webapps下的工程项目包,源码必须要打成artifact部署包才能部署在tomcat上),exploded的是解压之后的包,archive是压缩包war包(tomcat启动会自动压缩)
2,把该artifacts部署在tomcat上
Servlet
Servlet入门-获取参数
业务目的:客户端发送访问javaweb项目里的add.html页面(一个表单),服务器返回给客户端add.html,用户填写表单,然后点击提交,action=add,发送给服务器,服务器调用addServlet处理请求并返回。
要实现AddServlet需要继承HttpServlet(导入Servlet-api依赖)
服务器处理提交表单请求的servlet过程:
1,用户发送请求action=add
2,项目中,web.xml中找到url-pattern=/add --》第12行
3,找到11行的servlet-name=AddServlet
4,找到和servlet-mapping中servlet-name一致的servlet,找到第七行
5,找到第八行的servlet-class-》com.atiguigu.servlets.AddServlet
6,用户发送的post请求(method=post),因此tomcat执行AddServlet的doPost()方法
Servlet-处理请求乱码
Servlet的继承关系
1,继承关系
javax.servlet.Servlet接口
javax.servlet.GenericServlet抽象类
javax.servlet.http.HttpServlet
2.相关方法(service()重点)
javax.servlet.Servlet接口:
void initi(config) -- 初始化方法
void service(request,response) --服务方法
void destroy() -销毁方法
javax.servlet.GenericServlet抽象类
void service(request,response) -仍然是抽象的
javax.servlet.http.HttpServlet抽象子类:
void service(request,response) -不是抽象的
{
1,String method = req.getMethod(); //获取请求的方式
2,各种if判断,根据请求方式不同,决定调用不同的do方法
do get(){获取协议,http不支持get请求,返回405}
若子类只实现了do post(),客户端发送method=get,则调用父类httpservlet 的do get(),返回msg信息405报错。
3,httpServlet这个抽象类,do方法都差不多
}
总结
- 继承关系,HttpServlet继承GenericServlet(抽象类),GenricServlet实现Servlet
- Servlet中的核心方法,init(),service(),destroy()
service() - 当有请求发送给服务器,service()会自动响应(其实是tomcat容器调用的),在HttpServlet中我们会去分析请求的方式:倒是是get,post,head还是delete等等,然后再决定调用那个do开头的方法,在HttpServlet中这些方法默认都是405的实现,要我们子类去实现对应的方法,否则返回405错误
- 因此,我们在新建Servlet时,才回去考虑请求方法,从而决定重写那个do方法
Servlet的生命周期
ServletContext对象早于Servlet对象创建,前者是该web应用启动创建,后者在第一次http请求创建并初始化
1.生命周期:从出生到死亡,对应Servlet的三个方法:init(),service(),destroy()
2.默认情况下:第一次接受请求时,这个Servlet会进行实例化(调用构造方法),初始化(init()),然后服务(service()),第二次请求开始,每一次都是服务,当容器关闭时,其中的所有的servlet实例会被销毁(destroy()),调用销毁方法
3.- Servlei实例tomcat只会创建一个,所有的请求都是这个实例去响应
-第一次请求,tomcat才会实例化,初始化,好处:提高系统启动速度,对第一次请求不友好
-因此如果需要提高系统的启动速度,默认情况就是这样。如果提高响应速度,要设置Servlet的初始化时机
4.Servlet的初始化时机:
-默认是第一次请求时,实例化,初始化
-我们可以通过来设置servlet启动的先后顺序,数字越小启动越靠前,最小值0
5,Servlet在容器中是
单例的: 所有的请求都是同一个实例去响应
线程不安全: 一个线程需要根据这个实例的某个成员变量去作逻辑判断,但是这个时候另外个线程改变了这个成员变量的值
启发: 尽量不要再servlet中定义成员变量,如果不得不定义成员变量,那么不要去根据成员变量作逻辑判断
servlet-Http协议
HTTP:Hyper Text Transfer Protocol超文本传输协议。
请求响应包含两个部分:请求和响应,Http是无状态的。
**无状态:**有两个http请求发给服务器,服务器无法判断这两次请求是同一个客户端发来的,还是不同客户端发来的
请求报文
1 请求行:
作用:展示当前请求的最基本信息
- 请求方式
- 访问地址
- HTTP协议的版本
2 请求头
作用:通过具体的参数对本次请求进行详细的说明
格式:键值对,键和值之间使用冒号隔开
相对比较重要的请求消息头:
3 请求体
get方式没有请求体,但是有一个queryString
post方式,有请求体,form data
json格式,有请求体,request payload
响应报文
servle-session会话跟踪技术
1,Http是无状态的
无状态带来的问题:第一次请求是添加商品到购物车,第二次请求是结账。如果这两次请求无法区分是同一个用户,导致混乱,结账是别人的购物车。
解决:会话跟踪技术
- 客户端第一次发请求给服务器,服务器获取session,获取不到,则创建新的,然后响应给客户端
- 下次客户端再次给服务器发送请求,会把sessionID带给服务器,服务器就能获取到了,服务器根据cookies判断和上次请求是否是同一个就能区分不同客户端的请求。
常用的API:
request.getSession() =>获取当前的会话,没有则创建新的会话
request.getSession(true) =>效果和不带参数一样
request.getSession(false) =>获取当前会话,没有返回null,则不会创建新的
session.getId() =>获取sessionID
session.isNew() =>判断当前session是否是新的(session的有效时间半小时)
session.getMaxInactiveInterval() => session的不操作的间隔时间,半小时,半小时不操作断开
session.setMaxInavtiveInterval()
session.invalidate() =>强制性让会话立即失效
session保存作用域
同一个客户端(会话)有自己的作用域(容器),保存获取数据。
服务器内部转发和重定向
1 服务器内部转发
2 重定向
Thymeleaf -视图模板技术
**业务目的:**向index组件Servlet发送请求,tomcat处理service()从数据库查询得到的数据保存在session作用域,然后用thymeleaf将查询到的数据渲染到静态页面上
Service()方法如下:
@WebServlet("/index")//注册servlet
public class IndexServlet extends ViewBaseServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
FruitMapper mapper = sqlSession.getMapper(FruitMapper.class);
List<Fruit> list = mapper.getFruitList();
//保存到session作用域
HttpSession session = req.getSession();
session.setAttribute("fruitList",list);
//此处的index是视图名称
//thymeleaf会将这个逻辑视图名称对应到物理视图 名称上去
//逻辑视图名称:index
//物理视图名称:view-prefix+逻辑视图名称+view-suffix
//所以物理视图跳转的真实地址:/index.html
super.processTemplate("index",req,resp);
}
}
- 添加thymeleaf的jar包(maven 添加thymeleaf依赖)
2.新建一个Servlet类ViewBaseServlet
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ViewBaseServlet extends HttpServlet {
private TemplateEngine templateEngine;
@Override
public 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());
}
}
3.在web.xml添加配置
配置前缀 view-prefix
配置后缀vie-suffix
4.使得我们的Servlet继承ViewBaseServlet,使我们的Servlet拥有渲染数据到页面的功能,自动跳转到物理视图地址上。
public class IndexServlet extends ViewBaseServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
FruitMapper mapper = sqlSession.getMapper(FruitMapper.class);
List<Fruit> list = mapper.getFruitList();
//保存到session作用域
HttpSession session = req.getSession();
session.setAttribute("fruitList",list);
//此处的index是视图名称
//thymeleaf会将这个逻辑视图名称对应到物理视图 名称上去
//逻辑视图名称:index
//物理视图名称:view-prefix+逻辑视图名称+view-suffix
//所以物理视图跳转的真实地址:/index.html
super.processTemplate("index",req,resp);
}
5.使用thymeleaf标签实现渲染数据(使用数据库获得的数据保存在servlet作用域,用thymeleaf从作用域中取数据用从而修改静态页面)
th:if , th:unless ,th:each ,th:text
渲染的标签代码
原始静态页面
从数据库获取数据然后通过themleaf渲染得到后的页面
获得的数据库数据
保存作用域
request对象
**一次请求响应范围。**request对象内数据的存活范围就是在request对象的存活范围内。当客户端向服务器端发送一个请求,服务器向客户端返回一个响应后,该请求对象就被销毁了;之后再向服务器端发送新的请求时,服务器会创建新的request对象,request对象与之前的request对象没有任何关系,因此也无法获得在之前的request对象中所存放的任何数据。
重定向:两次请求响应,request.getArribute()不同作用域
请求转发:一次请求响应同一个作用域
session对象
**一次会话范围有效。**session对象内数据的存活范围也就是session对象的存活范围(只要浏览器不关闭,session对象就会一直存在),因此在同一个浏览器窗口中,无论向服务器端发送多少个请求,session对象只有一个。
application对象
一次应用程序范围有效(tomcat不关闭之前,所有客户端都可以获取application的数据)
MVC
dispatcherServlet(核心控制器)
1.根据请求的url获取servletPath,根据servletPath解析出名字
2.解析xml文件application.xml,读取所有的bean标签,存入一个hashmap<id,class的实例对象>
InputStream is = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(is);
NodeList beanNodes = document.getElementsByTagName("bean");
for (int i = 0;i < beanNodes.getLength();i++)
{
Node beanNode = beanNodes.item(i);
if(beanNode.getNodeType()==Node.ELEMENT_NODE) {
Element element = (Element) beanNode;
String id = element.getAttribute("id");
String className = element.getAttribute("class");
Object beanObject = Class.forName(className).newInstance();
setServletContext.invoke(beanObject,this.getServletContext());
beanMap.put(id, beanObject);
}
}
3.根据servletPath从map集合中得到对应的处理该请求的servlet类(controller)的实例,然后调用,然后从它的对象中调用对应operate方法
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码
req.setCharacterEncoding("UTF-8");
//假设url是 http://localhost:8080/javaweb/hello.do
//那么servletPath是 /hello.do
String servletPath = req.getServletPath();
// 第一步: servletPath /hello.do 改为 hello 或者fruit.do fruit
servletPath=servletPath.substring(1);
int lastDotIndex=servletPath.lastIndexOf(".do");
servletPath = servletPath.substring(0,lastDotIndex);
//第二步:hello 和 HelloController对应上 或者fruit FruitController
Object beanObject = beanMap.get(servletPath);
String operate = req.getParameter("operate");
if(operate==null||"".equals(operate))
{
operate= "index";
}
//获取每个servle对应的方法
Method[] methods = new Method[0];
try {
Method method = beanObject.getClass().getDeclaredMethod(operate,HttpServletRequest.class,HttpServletResponse.class);
if(method!=null){
method.setAccessible(true);
method.invoke(beanObject,req,resp);
}
else{
throw new RuntimeException("operate值错误");
}
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
提取视图通用代码
if(method!=null){
//controller组件中的方法调用
method.setAccessible(true);
Object returnObj= method.invoke(beanObject,req);
String methodReturnStr = (String)returnObj;
//视图处理
if(methodReturnStr.startsWith("redirect")){ //比如redirect:fruit.do
String redirectStr = methodReturnStr.substring("redirect".length());
resp.sendRedirect(redirectStr);
}
else {
super.processTemplate(methodReturnStr,req,resp); //比如edit
}
}
在核心控制器中统一获取参数以及视图处理
Method[] methods = beanObject.getClass().getDeclaredMethods();
for(Method method:methods){
if(operate.equals(method.getName()))
{
//1 .统一获取参数组
Parameter[] parameters = method.getParameters();
Object[]parameterValues = new Object[parameters.length];
for(int i=0;i<parameters.length;i++)
{
Parameter parameter = parameters[i];
String parameterName= parameter.getName();
System.out.println(parameterName);
if("req".equals(parameterName))
{
parameterValues[i]=req;
}
else if("resp".equals(parameterName))
{
parameterValues[i]=resp;
}
else if("session".equals(parameterName))
{
parameterValues[i]=req.getSession();
}
else {
String parameterValue = req.getParameter(parameter.getName());
parameterValues[i] = parameterValue;
}
}
// 2. controller组件中的方法调用
method.setAccessible(true);
Object returnObj= method.invoke(beanObject,parameterValues);
String methodReturnStr = (String)returnObj;
//3. 视图处理
if(methodReturnStr.startsWith("redirect")){ //比如redirect:fruit.do
String redirectStr = methodReturnStr.substring("redirect".length());
resp.sendRedirect(redirectStr);
}
else {
super.processTemplate(methodReturnStr,req,resp); //比如edit
}
}
}
获取真正的参数名要在设置中添加–parameters,不然参数名为arg0,arg1…,不是真正的形参名(id,name)
总结:
servlet-API
业务层的引入
IOC的实现
1,property 的name是当前bean标签对应实例的属性名(依赖类型的引用变量),ref是依赖类的bean标签的id值。每一个bean标签代表每一个组件(controller,service,dao)
Ioc实现
1.根据id值获取对应类的实例,存放在map容器中
InputStream is = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(is);
NodeList beanNodes = document.getElementsByTagName("bean");
for (int i = 0;i < beanNodes.getLength();i++)
{
Node beanNode = beanNodes.item(i);
if(beanNode.getNodeType()==Node.ELEMENT_NODE) {
Element element = (Element) beanNode;
String id = element.getAttribute("id");
String className = element.getAttribute("class");
Object beanObject = Class.forName(className).newInstance();
beanMap.put(id, beanObject);
}
}
2.遍历所有bean元素结点的子元素property节点,将ref对应的实例赋值给该bean标签对应实例的name属性,完成解除该组件和依赖组件的耦合关系
Filter
- Filter也属于Servlet规范
- 使用Filter步骤:新建类实现Filter接口,然后重写其中的三个方法:init,doFilter,destroy,配置Filter,可以用@WebFilter(拦截的servlet的url-pattern)),也可以用,
3.过滤器也可以拦截多个请求,和servlet一样,可以设置通配符,例如@WebFilter(“*.do”)表示拦截所有以.do结尾的请求
4.过滤器链
如果采取的是注解的方式进行配置(@WebServlet),那么过滤器的拦截顺序是按照全类名的先后顺序
如果采取的是xml的方式配置,那么按照配置的先后顺序进行排序
5.将中央控制器的设置编码统一到过滤器完成
事务管理
假设该业务有三个DAO操作,有两个成功,一个失败回滚,那么该业务执行不成功。因此,事务管理不能在以DAO层的单精度方法为单位,应该以业务层的方法为单位。
事务管理的实现
1.创建一个Filter实现类,实现事务管理,该事务中每一个DAO操作都成功则事务完成提交,有一个DAO操作失败就会回滚。
SqlSessionUtil类(获取连接,新建连接存入threadlocal,关闭连接设置threalocal为空)
使所有dao操作使用同一个链接(从threadlocal中获取)
public class SqlSessionUtil {
private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
public static SqlSession createSqlSession() throws IOException {
SqlSession sqlSession=null;
try{
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
sqlSession = factory.openSession(false);
}catch(IOException e){
e.printStackTrace();
}
return sqlSession;
}
public static SqlSession getSqlSession() throws IOException {
SqlSession sqlSession = threadLocal.get();
if(sqlSession==null)
{
sqlSession = createSqlSession();
threadLocal.set(sqlSession);
}
return sqlSession;
}
public static void closeSqlSession() throws SQLException {
SqlSession sqlSession = threadLocal.get();
if(sqlSession==null){
return ;
}
if(sqlSession.getConnection()!=null)
{
sqlSession.close();
threadLocal.set(null);
}
}
ThreadLocal
方法set(),get()(同一个线程内共享)
set方法在当前线程存储数据,get从当前线程获取数据。
set方法源码:
get 方法源码:
Listener
参考https://heavy_code_industry.gitee.io/code_heavy_industry/pro001-javaweb/lecture/chapter11/verse02.html
总结
Cookie
https://heavy_code_industry.gitee.io/code_heavy_industry/pro001-javaweb/lecture/chapter09/verse02.html