学习资源
学习笔记
- 查漏补缺
- 重点部分-代码覆盖
一、HTML和CSS
1. HTML
- 特殊字符
- HTML中输出连续空格请使用
- <
< - >
>
- HTML中输出连续空格请使用
- table
- tr 行标签
- dth 表头标签
- td 单元格标签
- 表格属性:
- 对齐方式
align="center"居中 - 单元格间距
cellspacing - 跨列属性
colspan - 跨行属性
rowspan
- 对齐方式
- form
- input
- value 属性 默认值
- type 属性
- radio 单选框
- name 通过设置相同name属性来分组)
- checked=”checked” 默认选中
- 下拉列表框
<select><option>...</option></select>- option可以添加
selected="selected"来表示默认选中
- option可以添加
- reset 重置按钮
- hidden 隐藏域 (当需要提交一些不需要用户参与的信息时可以使用隐藏域)
- radio 单选框
- action 设置提交的服务器地址
- method 设置提交的方式 GET(默认值)或 POST
- 数据没有发送给服务器
- 表单项中没有 name 属性
- 单选、复选(下拉列表的 option 标签)都需要添加 value 属性
- 表达项不在 form 中
- input
- p 段落标签
- 默认会在段落的上方和下方各空出一行
2. CSS
- 组合选择器
选择器1, 选择器2, 选择器3
多个选择器共用同一个css代码
二、JavaScript
- arguments 隐形参数,类似java的可变长参数
- 常用事件
- onload 加载完成 执行完毕后,浏览器自动执行的事件
- onclick 点击
- onblur 失去焦点
- onchange 内容变更
- onsubmit 提交
- 正则表达式
- 量词
- 至少一个
- 0个或多个
- ? 0个或1个
- {x} x个
- {x, y} 至少x个,至多y个
- {x, } 至少x个
- $ 结尾
- ^ 开头
- 量词
三、jQuery
- js类库,兼容问题
- $ 是一个函数
- 绑定一个按钮响应事件
- 绑定标签对象
- 使用标签对象.click
- 核心函数传参 $()
- 传入 函数,相当于 window.onload = function()
- 传入 HTML字符串,会创建一个HTML标签对象
- 传入 选择器字符串
$('#id属性值')id选择器$('.class属性值')类型选择器$('标签名')标签名选择器,根据指定的标签名查询标签对象
- 传入 DOM对象 会把dom对象转换为jQuery对象
- jQuery对象的本质:
dom对象的数据 + jQuery提供的一系列功能函数
- jQuery与DOM 的属性和方法不互通
- DOM —> jQuery:
$(DOM) - jQuery —> DOM:
$obj[ 数组下标 ] - 选择器
p.xxx含义是匹配 p标签 且 class=”xxx” 的元素- .css() 方法可以设置或者获取css代码
$('#xxx').css('background-color', 'red'); - 层级选择器
$('ancestor descendant')匹配给定元素 ancestor 的所有子孙元素 descendant$('parent>child')直接后代选择器,匹配元素 parent 所有子元素 child$('prevSibling+nextSibling')匹配所有prevSibling后面的nextSibling元素,无所谓层级$('prev~sibling')匹配prev元素后所有同级sibling元素
$(document).ready(function() {})是$(function() {})的简写形式
- 属性操作
- html() == DOM .innerHTML()
- text() == DOM .innerText()
- val() == DOM .value()
- attr() 设置或获取属性值
$('xxx').attr('key', 'value'); // 设置,不推荐操作checked、readOnly、selected、disabled等等 - prop() 设置或获取属性值
$('xxx').prop('key', 'value'); // 设置,最推荐操作attr不推荐操作的标签元素
- 点击事件内
return false可以阻止标签的默认行为 - confirm() 是js提供的dialog,返回true代表用户点击了确定,否则就是点击了取消
- 增删改
- 内部插入
- appendTo() a.appendTo(b) 把a插入b子元素末尾
- prependTo() a.prependTo(b) 把a插入b子元素开头
- 外部插入
- insertAfter() a.insertAfter(b) 把a插入b同级元素后面
- insertBefore() a.insertBefore(b) 把a插入b同级元素前面
- 替换
- replaceWith() a.replaceWith(b) 用b替换a
- replaceAll() a.replaceAll(b) 用a替换到所有b
- 删除
- remove() a.remove() 删除a
- empty() a.empty() 清空a标签内的内容
- 内部插入
- css操作
- addClass() 添加样式
- removeClass 删除样式
- toggleClass 有则删除,没有就添加样式
- offseet 获取或设置元素坐标,内部设置 top 和 left 两个属性
- jQuery动画
- 基本动画
- show()
- hide()
- toggle() 可见就隐藏,不可见就显示
- 以上方法都有以下参数
- 动画执行时长,毫秒为单位
- 动画的回调函数
- 淡入淡出动画
- fadeIn()
- fadeOut()
- fadeTo() 在指定的时长内慢慢的将透明度修改到指定的值
- fadeToggle()
- 基本动画
- jQuery事件执行顺序
- 先执行jQuery页面加载完成事件,在执行window原生js页面加载完成事件
- jQuery待页面加载完成是指浏览器内核解析好页面标签创建DOM对象后就执行
- 原生js的页面加载完成后,除了要等浏览器内核解析完标签创建好DOM对象,还要等标签显示时需要的内容加载完成
- 执行次数
- 原生js只会执行最后一次的函数
- jQuery依次按顺序都执行
- 先执行jQuery页面加载完成事件,在执行window原生js页面加载完成事件
- jQuery事件
- click 既可以绑定也可以用于触发单击事件。不传函数就可以当作是一次点击
- mouseover 鼠标移入事件
- mouseout 鼠标移出事件
- bind 可以给元素一次性绑定一个或多个事件
.bind('click mouseover mouseout',function() {}); - one 使用跟bind一样,但是绑定的事件只会执行一次
- live 也是用来绑定事件,可以用来绑定选择器匹配的所有元素的事件,即使元素是后来创建的
- unbind 取消事件绑定,也可以传递多个,用空格区分
- 事件冒泡:阻止事件冒泡只需要在子元素事件中
return false 获取事件对象
原生js
window.onload = () => {document.getElementById('areaDiv').onclick = () => {console.log(event);};};
jQuery
$(() => {$('#areaDiv').click((event) => {console.log(event);});});
四、XML
1. XML简介
创建方式:[new file] -> [_.xml]
2.1 文档声明
<?xm version="1.0" encoding="utf-8" ?>
- version xml 版本
- encoding xml文件编码
2.2 元素(标签)
<标签名>内容......</标签名>
- xml元素是指从开始标签到结束标签的部分,元素内可包含元素
- 元素名称规范
- 名称可包含字母、数字以及其他字符
- 不能以数字或标点符号开始
- 不能以“xml”(“XML”或者“Xml”)开始
- 不能包含空格
2.3 xml属性
<标签名属性名=属性值>内容......</标签名>
- 每个属性值都必须用 引号 引起来
- 属性名和标签名规则一致
2.4 xml注释
<!--注释内容-->
2.5 其他规则
- 所有XML元素都必须有关闭标签(所有元素都要闭合)
- 大小写敏感
- 必须正确的嵌套
- 必须有根元素(顶级元素)且唯一,类似vue里的root
- 特殊字符
3. XML解析技术
<?xml version="1.0" encoding="utf-8" ?><!--这里是多行注释声明方式--><books><!--book表示一个图书信息sn属性表示图书序列号--><book sn="SN1234456"><name>时间简史</name><author><!-- CDATA 文本区域 --><![CDATA[<<<<<<<<]]>霍金</author><price>76</price></book><book sn="SN1234457"><name>回明</name><author>月关</author><price>98.82</price></book></books>
import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;import org.junit.Test;import java.math.BigDecimal;import java.util.List;public class Dom4jTest {@Testpublic void testDom4j () throws Exception {SAXReader saxReader = new SAXReader();Document document = saxReader.read("src/books.xml");System.out.println(document);}@Testpublic void testDom4j1 () throws Exception {// 1. 读取xml文件SAXReader saxReader = new SAXReader();// Junit测试中,相对路径从模块名开始算Document document = saxReader.read("src/books.xml");// 2. 通过document对象获取根元素Element rootElement = document.getRootElement();// System.out.println(rootElement);// 3. 通过根元素获取book标签对象// elements 和 element 都是通过标签名查找子元素List<Element> elements = rootElement.elements("book");for (Element book: elements ) {// asXML() 把标签对象转换为标签字符串// System.out.println(book.asXML());Element nameElement = book.element("name");// getText() 获取标签中文本内容String nameText = nameElement.getText();// elementText 获取指定标签名的文本内容String priceText = book.elementText("price");String authorText = book.elementText("author");// attributeValue 获取属性值String sn = book.attributeValue("sn");Book bookObj = new Book(sn, nameText, new BigDecimal(priceText), authorText);System.out.println(bookObj);}// 4. 遍历,处理每个book标签}}
五、Tomcat
- Web资源分类
- 静态资源
- html
- css
- js
- txt
- mp4
- 图片
- 动态资源
- jsp页面
- Servlet程序
- 静态资源
- Tomcat服务器和Servlet版本对应关系

- 当前企业最广泛使用Tomcat 7 / 8,Servlet 2.5 应用最广泛
1. Tomcat使用
1.1 目录介绍
| 文件夹名 | 说明 | | —- | —- | | bin | tomcat可执行程序 | | conf | 配置文件 | | lib | jar包 | | logs | 运行时输出的日志 | | temp | 运行时临时数据 | | webapps | 部署到web工程 | | work | 工作时目录,jsp翻译为Servlet源码与Session钝化的目录 |
1.2 启动
【bin】-【startup.bat】双击启动
测试启动是否成功:
这里的8080是默认端口号,但是我为了安全已经修改为了 *26
- 另一种启动方式:命令行cd到tomcat安装目录bin下执行
catalina run(这种方式不需要配置JAVA_HOME环境变量也能启动tomcat服务器)
1.3 关闭
- 关闭服务器窗口
- bin 目录下的 shutdown.bat 双击
1.4 修改端口号
- 进入以下tomcat安装目录【conf】-【server.xml】,修改以下代码
69#<Connector port="8080" ... />将 port 修改为需要的端口号(1 ~ 65535) - 修改完tomcat配置后要重启tomcat服务器
HTTP默认端口号是 80
1.5 如何部署web工程到Tomcat服务器
- 只需要将web工程直接拷贝到 【webapps】文件夹内即可
- 或者在【conf】-【Catalina】-【localhost】新建一个 XML 文件,添加以下配置
<Context path="/abc" docBase="绝对路径文件夹" /> <!-- path表示工程访问路径,docBase表示工程目录路径 -->
当没有输入工程名时,访问的其实是 ROOT 工程 当仅输入到工程名没具体指明html文件名时,默认访问 index.html 文件
六、Servlet
- What?
- Servlet 是 JavaEE 规范之一。规范就是接口
- JavaWeb三大组件之一。Servlet程序、Filter过滤器、Listener监听器
- 运行在服务器上的java小程序,可以接受客户端发送的请求,响应数据给客户端
- How?
- 复制tomcat安装目录下的【lib】-【servlet-api.jar】,导入到项目中
- 新创建空白项目或者模块,在模块上右键,选择【添加模块的支持…】选择【Web Service】前面打勾即可
- 新创建类实现
javax.servlet.Servlet接口及其initgetServletConfigservicegetServletInfodestroy五个接口中的抽象方法 - web.xml 配置 servlet 访问地址
1. 技术
1.1. 生命周期
- servlet构造器方法
- init初始化方法
第一次访问创建servlet会调用
- service方法
每次访问都会调用
- destroy销毁方法
web工程停止的时候调用
1.2. 请求分发
/*** 处理请求和响应* @param servletRequest* @param servletResponse* @throws ServletException* @throws IOException*/@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("3 service === 有人访问Servlet了!!!");// 因为类型转换后才能获得请求方法HttpServletRequest request = (HttpServletRequest) servletRequest;String method = request.getMethod();if ("GET".equals(method)) {doGet();} else if ("POST".equals(method)) {doPost();}}
1.3. 通过继承HttpServlet实现Servlet程序
public class ServletTest1 extends HttpServlet {/*** get请求* @param req* @param resp* @throws ServletException* @throws IOException*/@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doGet(req, resp);System.out.println("do get");}/*** post请求* @param req* @param resp* @throws ServletException* @throws IOException*/@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);System.out.println("do post");}}
1.4. 通过IDEA创建servlet
右键【新建】-【创建新 Servlet】
1.5. Servlet 类的继承体系
2. ServletConfig 类
Servlet和ServletConfig 都由Tomcat负责创建,我们仅负责使用
Servlet默认第一次访问时创建,ServletConfig每个Servlet程序创建时就创建一个ServletConfig对象
2.1 作用
- 获取 Servlet 程序别名 servlet-name 的值
- 获取初始化参数 init-param
- 获取 ServletContent 对象
3. ServletContext类
3.1 What?
- ServletContext是一个接口,表示Servlet上下文对象
- 一个web工程,只有一个ServletContext对象实例
- 域对象
- 可以向map一样存取数据的对象
- 存取数据的操作范围,整个web工程
- web工程部署移动的时候创建。在web工程停止的时候销毁
3.2 作用
- 获取web.xml 配置的上下文参数 context-param
- 获取当前的工程路径,格式: /工程路径
- 获取部署后在磁盘绝对路径
4. HTTP协议
- 无状态、应用层协议,运行于TCP协议基础上。
- 允许任意类型数据,数据类型由Content-Type标识




5. HttpServletRequest 类
- Tomcat将请求得到HTTP协议信息解析后封装到 Request 对象中,然后传递到 service 方法(doGet 和 doPost)。我们可以通过 HttpServletRequest 对象获取所有请求的信息
请求方法
- getRequestURI 请求资源路径
- getRequestURL 请求统一资源定位符(绝对路径)
- getRemoteHost ip地址
- getHeader 请求头
- getParamter
- getParamterValues 多个请求参数时获取请求参数
- getMethod
- setAttribute 设置域数据
- getAttribute 获取域数据
- getRequestDispatcher 获取请求转发对象
请求的转发
服务器收到请求后从一个资源跳转到另一个资源
- 特点
- 浏览器地址栏没发生变化
- 一次请求
- 共享Request域数据
- 可以转发到WEB-INFO下(同一目录下的页面都可以访问跳转)
- 不可以访问工程以外的资源(会报404错误)
- base 标签
可以设置当前页面所有相对路径工作时,参照哪个路径来跳转
base内最后一位的 / 不能省略
- “/”意义
- 浏览器解析:
http://ip:port/ - 服务器解析:
http://ip:port/工程路径 - 特殊情况:response.sendRediect(“/“); 把斜杠发送给浏览器解析,得到
http://ip:port/
- 浏览器解析:
5. HttpServletResponse 类
每次请求进来,Tomcat服务器都会创建一个 Response 对象传递给 Servlet 程序使用。
- 两个输出流
- 字节流 getOutputStream(); // 常用于下载(二进制数据)
- 字符流 getWriter(); // 常用于回传字符串(常用)
两个流同时只能使用一个。
- 响应乱码解决方案 ```java response.setCharacterEncoding(“UTF-8”);
// 通过响应头,设置浏览器也使用 UTF-8 字符集 response.setHeader(“Content-Type”, “text/html;charset=UTF-8”);
PrintWriter writer = response.getWriter(); writer.write(“is response!!! 北京”);
方法二:```sqlresponse.setContentType("text/html; charset=UTF-8");PrintWriter writer = response.getWriter();writer.write("is response!!! 北京");
- 请求重定向
客户端给服务器发请求,服务器告诉客户端,我提供一些地址,你去新的地址访问。(因为之前地址已经被废弃)
方案一:
特点:
- 浏览器地址栏发生变化
- 两次请求
- 不共享Request域数据
- 不能访问WEB-INFO下资源
- 可以访问工程外的资源
// 状态码:302,表示重定向response.setStatus(302);// 设置响应头,说明新地址response.setHeader("Location", "http://localhost:8080/myservlet/response4");
方案二(推荐此方案):
// 方案二:response.sendRedirect("http://localhost:8080/myservlet/response4");
三层架构
项目结构
七、JSP
- .jsp 文件跟普通 html 文件一样,可以直接访问 xx.jsp
- jsp文件本质上是一个 servlet 程序
- 第一次访问jsp页面。Tomcat服务器会把jsp页面翻译成一个java源文件。并且对他进行编译成为 .class 字节码程序
1. 头部page指令


2. jsp中常用的脚本
2.1 声明脚本<%! 声明java代码 %> java类定义属性和方法甚至是静态代码块,内部类等
<%-- 1. 声明类属性 --%><%!private Integer id;private String name;private static Map<String, Object> map;%><%-- 2. 静态代码块 --%><%!static {map = new HashMap<String, Object>();map.put("key1", "value1");map.put("key2", "value2");map.put("key3", "value3 ");}%><%-- 3. 声明类方法 --%><%!public int abc() {return 12;}%><%-- 4. 声明内部类 --%><%!public static class A {private Integer id = 16;private String abc = "abc";}%>
2.2 表达式脚本<%= 表达式 %> 在jsp页面上输出数据
- 所有表达式脚本都被翻译到 _jspService 方法中
- _jspService 方法中的对象都可以使用
- 被翻译成 out.print() 输出到页面上
- 不能以分号结束
2.3 代码脚本<% 代码脚本 %>
可以在jsp页面编写需要的功能(java语句 )
- 都在 _jspService 方法中
- 可以使用 _jspService 现有对象
- 多个代码脚本快组合完成一个java语句
- 可以和表达式脚本一期组合使用
3. 注释
3.1 html注释<!-- 注释内容 -->以out.writer 输出到客户端
3.2 java注释
java源代码中
<%// 单行注释/* 多行注释 */%>
4. 9大内置对象

5. 4大域对象
PageContext(PageContextImpl 类) 当前jsp页面有效、
request (HttpServletRequest类) 一次请求有效、
session (HttpSession 类) 一个会话范围内有效、
application (ServletContext 类) 整个web工程范围内有效
- 功能一样,存取范围不一样
- 使用优先顺序是从小到大的范围顺序相同 pageContext —> request —> session —> application
6. jsp中的out输出和response.getWriter 输出的区别

- 所以统一在页面中使用 out 输出,避免顺序打乱
- out.writer() 输出字符串没有问题
- out.print() 输出任意数据没有问题,都是先转换为字符串调用的write输出,统一使用此即可,安全。
7. jsp常用标签
7.1 jsp静态包含
<%@ include file="" %>
- file属性指定要包含的jsp页面的路径
- 地址中第一个 / 表示为
http://IP:PORT/工程路径/,映射到代码的web目录 - 特点
- 不会翻译jsp页面
- 把包含的jsp页面代码拷贝到包含的位置执行输出
7.2 jsp动态包含
<jsp:include page="/include/footer.jsp"></jsp:include>
- page属性指定要包含的jsp页面的路径
- 把被包含的内容拷贝到包含的位置执行输出
- 特点
- jsp页面翻译为java代码
- 含底层代码调用被包含jsp页面执行输出
- 可以传递参数

7.3 jsp标签-转发
<jsp:forward page=""></jsp:forward>
8. Listener 监听器
三大组件之一(Servlet、Filter、Listener)
- 接口
- 监听某种事物的变化,通过回调函数,反馈给客户(程序)相应处理
8.1 ServletContextListener 监听器
- 监听 ServletContext 对象的创建和销毁
- web工程启动时创建,web工程停止的时候销毁
- 监听到创建和销毁之后都会分别调用 ServletContextListener 监听器的方法反馈
八、EL表达式
1. 概述
- Expression Language 表达式语言
- 替代jsp页面中的表达式脚本在jsp页面中进行数据的输出
- EL表达式输出数据比jsp表达式简洁
- EL为空时无输出,不像普通表达式输出 “null”
${ 表达式 }
2. 搜索域数据的顺序
主要用于在jsp页面中输出数据
EL表达式按照域数据从小到大的顺序搜索
pageContext —> request —> session —> application
3. 运算
3.1 关系运算
3.2 逻辑运算
3.3 算数运算
3.4 empty 运算
- 判断一个数据是否为空,空——> true,非空——> false
- 以下情况为空:
- null
- 空船
- Object类型数据,长度为0
- list集合,元素个数为0
- map集合,元素个数为0
${ empty 变量名 }
3.5 三元运算${表达式1 ? 表达式2 : 表达式3}
3.6 点运算,中括号运算
. 某属性的值
[] 集合中某元素的值,还可以输出map中特殊key的值
4. 11个隐含对象




九、JSTL 标签库
是一个不断完善的开放源代码的JSP标签库,是为了替换代码脚本,使得整个jsp页面变得更加简洁
- 接入步骤
- 接入jar包
- 使用taglib 指令引入标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- 使用taglib 指令引入标签库


<c:choose><c:when test="${12 == 12}"><h1>test</h1></c:when><c:otherwise><h2>test1</h2></c:otherwise></c:choose>
- 标签里不能使用 html 注释
- otherwise 表示剩下的情况
- when标签的父标签一定要时choose标签



- start表示开始索引
- end表示结束索引
- step表示步长值

十、文件的上传和下载
1. 上传
要求
- 要有一个form标签,且method为post请求
- form标签
enctype属性值必须为multipart/form-data - 在form标签中使用
input type=file添加上传的文件 - 编写服务器代码接受,处理上传的数据
request说明

- commons-fileupload.jar 常用API介绍说明
- commons-fileupload.jar 需要依赖 commons-io.jar,所以我们首要任务是导入这两个jar包
- 常用类
- ServletFileUpload类,解析上传的数据;
- FileItem类,表示每一个表单项
- 常用方法
boolean ServletFileUpload.isMultipartContent(HttpServletRequest request);
判断当前上传的数据格式是否是多段的格式。public List<FileItem> parseRequest(HttpServletRequset request)
解析上传的数据boolean FileItem.isFormField()
判断当前表单项是普通表单项还是上传的文件类型。true表示普通类型的表单项,false表示上传的文件String FileItem.getFieldName()
获取表单项的name属性值String FileItem.getString()
获取当前表单项的值String FileItem.getName()
获取上传文件名void FileItem.write(file)
上传文件写道参数file所指向的硬盘位置
2. 下载
- 常用API说明:
- response.getOutputStream()
- servletContext.getResourceAsStream();
- servletContext.getMimeType()
- response.setContentType()

- 下载文件含中文导致的乱码问题
- IE和谷歌
response.setHeader(``"Content-Disposition"``, ``"attachment;filename=" ``+URLEncoder**.``_encode_``("``中国``.png"``,"UTF-8"``)**)``; - 火狐
BASE64编码解码解决中文乱码问题 ```java // 创建一个base64编码器 String content = “中文”; BASE64Encoder base64Encoder = new BASE64Encoder(); String encode = base64Encoder.encode(content.getBytes(“UTF-8”));
- IE和谷歌
// 创建一个base64解码器 BASE64Decoder base64Decoder = new BASE64Decoder(); byte[] bytes = base64Decoder.decodeBuffer(encode); String newContent = new String(bytes, “UTF-8”);
所以可以修改为<br />`response.setHeader(``"Content-Disposition"``, ``"attachment;filename==?UTF-8?B?" ``+ ``new ``BASE64Encoder().encode(``"``中国``.png"``.getBytes(``"UTF-8"``)) + ``"?="``)``;`<a name="oMXGe"></a>## 十一、Cookie和Session<a name="rhkLp"></a>### 1. Cookie- 服务器通知客户端保存键值对的一种技术- 客户端存储cookie后,每次请求都发送给服务器- 每个cookie不能超过4kb- 服务器获取cookie:**`response.getCookies().Cookie[]`**- 修改Cookie:- 方案一:- 创建一个同名的Cookie对象- 构造器赋予新的Cookie值- 调用 **`response.addCookie(NewCookie);`**- 方案二:- 查找到需要修改的Cookie对象- 调用 setValue() 方法赋予新的Cookie值- 调用response.addCookie(NewCookie);- Cookie的值不能包含 空格、方括号、圆括号、等号、逗号、双引号、斜杠、问号、at符号、冒号、分号。如果需要保存要使用base64编码- 生命控制- 如何管理Cookie什么时候销毁(删除)- setMaxAge- 正数,表示指定的秒数后过期- 负数,表示浏览器关闭,Cookie就删除- 零,表示马上删除Cookie- 有效Path设置- 可以过滤哪些Cookie可以发送给服务器,哪些不发送- path通过请求地址过滤- 利用Cookie用户免登录<a name="66GFe"></a>### 2. Session- what?- session是一个接口(HttpSession)- 会话,维护客户端和服务器之间关联的一种技术- 每个**`客户端`**都有自己的一个session会话- 保存用户登录后的信息- how?- 创建和获取的API一样- **`request.getSession()`**- 第一次调用:创建Session会话- 之后调用都是,获取前面创建好的session会话对象- **`isNew()`** 判断session是不是刚创建的(新的)- true 刚创建- false 获取之前创建的- 每个会话都有一个唯一的id值,**`getId()`** 获取session的会话id值- 生命周期控制- **`setMaxInactiveInterval(int interval)`** 设置session超时时间,超过指定时长,session被销毁,单位为秒。- 默认超时时长为 30 分钟,tomcat配置文件中配置了tomcat中session超时时间- 如果希望修改配置中超时时长,可以在web工程中配置相同字段,并修改时长。```xml<session-config><session-timeout>20</session-timeout> <!-- 超时时长,单位为分 --></session-config>
- 如果需要单独修改个别session超时时长,就需要调用api实现
- session超时指的是,客户端两次请求的最大间隔时长,当不间断请求时,session不会超时,每次请求都会重新刷新请求超时时间从0重新开始计时,直到两次请求间隔超过超时时间。
- 设置为负数,表示永不超时(极少使用)
invalidate()使得当前session会话立即超时无效
- 浏览器和Session之前关联的技术内幕

session底层基于cookie技术实现。
十二、Filter过滤器
- 三大组件之一:Servlet程序、Listener监听器、Filter过滤器
- JavaEE规范,接口
- 拦截请求,过滤响应
- 应用场景:权限检查、日记操作、事务管理
- demo:
- 要求web工程下的admin目录内所有资源,都必须用户登录后才能访问。
- 方案一:判断session中是否有用户登录信息,缺陷只能在jsp文件中判断,html中是无效的。
- 方案二:使用filter拦截器
- 使用步骤
- 编写类实现Filter接口
- 实现过滤方法doFilter()
- web.xml 配置 Filter 拦截路径
- 生命周期
- 构造器方法
- init初始化方法
以上在web工程启动的时候就会执行
- doFIlter过滤方法
每次拦截到请求就会执行
- destroy销毁方法
停止web工程的时候就会执行
- FilterConfig 类
- 配置文件类
- tomcat创建filter的时候,会同时创建一个filterConfig类,包含了Filter配置文件的配置信息
- 获取filter过滤器配置内容
- FilterChain 过滤器链(多个过滤器如何一起工作)

- 执行顺序是由web.xml中的配置的顺序确定的
- 特点:
- 所有filter和目标资源默认执行在同一个线程中
- 多个filter共同执行的时候,使用同一个 Request 对象
- Filter的拦截路径
- 精确匹配
<url-pattern>``/target.jsp``</url-pattern>请求地址必须为:http://ip:port/工程路径/target.jsp
- 目录匹配
<url-pattern>``/admin/*``</url-pattern>请求地址必须为:http://ip:port/工程路径/admin/*
- 后缀名匹配(不能以 / 开始)
<url-pattern>``*.html``</url-pattern>请求地址必须为.html为结尾- Filter只关心请求的地址是否匹配,不关心请求的资源是否存在
十三、JSON、AJAX、i18n
1. JSON
- 独立于语言的文本格式
- 轻量级(和xml做比较)、数据交换(客户端和服务器交互)
- json在java中的应用
- JavaBean和json的互转
- List和Json的互转
- map和Json的互转
2. AJAX
- 浏览器通过js异步发起请求,局部更新页面的技术
- 局部更新
- 浏览器地址栏不会变更
- 页面内容不会丢失
- jQuery中的AJAX请求
- $.ajax
- url
- type 请求类型,get/post
- data
- $.ajax
格式有两种:
1. name=value&name=value1. {key:value,dkey:value}- success 响应回调函数- dataType 响应数据类型- text 纯文本- xml- json
- $.get 和 $.post
- url
- data 仅支持name=value&name=value格式字符串
- callback 成功的回调函数
- type 返回的数据类型
- $.getJSON
- url
- data
- callback
- 表单序列化 serialize
- 可以把表单中所有表单项的内容都获取到,并以 name=value&name=value 的形式拼接
3. i18n
- Locale对象标识不同的时区、位置、语言
- zh_CN 中国,中文
- en_US 美国,英文

附录:
附录一:书城项目
第二阶段
- 步骤:
- 创建数据库和用户表
drop database if exists JavaWeb;create database JavaWeb;use JavaWeb;create table t_user (`id` int primary key auto_increment,`username` varchar(20) not null unique,`password` varchar(32) not null,`email` varchar(200));insert into t_user(`username`, `password`, `email`) values('admin', 'admin', 'admin@163.com');select * from t_user;
- 创建对应于用户表的用户类bean ```java package bean;
public class User { private int id; private String username; private String password; private String email; public User() { } public User(int id, String username, String password, String email) { this.id = id; this.username = username; this.password = password; this.email = email; } @Override public String toString() { return “User{“ + “id=” + id + “, username=’” + username + ‘\’’ + “, password=’” + password + ‘\’’ + “, email=’” + email + ‘\’’ + ‘}’; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() {return username;} public void setUsername(String username) {this.username = username;} public String getPassword() {return password;} public void setPassword(String password) {this.password = password;} public String getEmail() {return email;} public void setEmail(String email) {this.email = email;} }
- JdbcUtil```java# web.propertiesdriverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://【IP】:【PORT】/【数据库名】username=【用户名】password=【密码】initialSize=10maxActive=10
package util;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;import java.io.InputStream;import java.sql.*;import java.util.Properties;public class JdbcUtils {private static DataSource sourceDruid;static {try {Properties pros = new Properties();InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("web.properties"); // getResourceAsStream 的首路径为 src/pros.load(is);sourceDruid = DruidDataSourceFactory.createDataSource(pros);} catch (Exception e) {e.printStackTrace();}}/*** 获取数据库连接* @return* @throws Exception*/public static Connection getConnection() throws Exception {return sourceDruid.getConnection();}/*** 关闭资源* @param conn* @param statement*/public static void close(Connection conn, Statement statement) {if (conn != null) {try {conn.close();} catch (SQLException throwable) {throwable.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException throwable) {throwable.printStackTrace();}}}/*** 【重载】扩展原先关闭资源函数* @param conn* @param statement* @param resultSet*/public static void close(Connection conn, Statement statement, ResultSet resultSet) {close(conn, statement);if (resultSet != null) {try {resultSet.close();} catch (SQLException throwable) {throwable.printStackTrace();}}}}
- BaseDAO ```java package dao;
import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.ScalarHandler; import util.JdbcUtils;
import java.sql.*; import java.util.List;
public class BaseDAO { private QueryRunner runner = new QueryRunner();
/*** insert/update/delete* @return 返回-1,操作失败;其他表示影响的行数*/public int update(String sql, Object ...args) {Connection conn = null;try {conn = JdbcUtils.getConnection();return runner.update(conn, sql, args);} catch (Exception e) {e.printStackTrace();} finally {JdbcUtils.close(conn, null);}return 0;}/*** 仅返回一条语句的sql语句* @param type* @param sql* @param args* @param <T>* @return*/public <T> T queryValue(Class<T> type, String sql, Object ...args) {Connection conn = null;try {conn = JdbcUtils.getConnection();return runner.query(conn, sql, new BeanHandler<T>(type), args);} catch (Exception e) {e.printStackTrace();} finally {JdbcUtils.close(conn, null);}return null;}/*** 查询返回List* @param type* @param sql* @param args* @param <T>* @return*/public <T> List<T> queryForList(Class<T> type, String sql, Object ...args) {Connection conn = null;try {conn = JdbcUtils.getConnection();return (List<T>) runner.query(conn, sql, new BeanHandler<T>(type), args);} catch (Exception e) {e.printStackTrace();} finally {JdbcUtils.close(conn, null);}return null;}/*** 返回一行一列的语句* @param sql* @param args* @return*/public Object queryForSingleValue(String sql, Object ...args){Connection conn = null;try {conn = JdbcUtils.getConnection();return runner.query(conn, sql, new ScalarHandler(), args);} catch (Exception e) {e.printStackTrace();} finally {JdbcUtils.close(conn, null);}return null;}
}
- UserDAO```javapackage dao;import bean.User;import java.sql.Connection;import java.util.List;/*** 此接口用于规范对于customerd表的常用操作*/public interface UserDAO {/*** 根据用户名查询用户信息* @param username 用户名* @return null/用户信息*/public User queryUserByUsername(String username);/*** 保存用户信息* @param user 用户* @return*/public int saveUser(User user);/*** 根据用户名和密码查询用户信息* @param username 用户名* @param password 密码* @return*/public User queryUserByUsernameAndPassword(String username, String password);}
- UserDAOImpl ```java package dao;
import bean.User;
/**
接口UserDAO的实现类 */ public class UserDAOImpl extends BaseDAO
implements UserDAO { @Override public User queryUserByUsername(String username) {
String sql = "select `id`,`username`,`password`, `email` from t_user where username = ?";return queryValue(sql, username);
}
@Override public User queryUserByUsernameAndPassword(String username, String password) {
String sql = "select `id`,`username`,`password`,`email` from t_user where username=? and password=?";return queryValue(sql, username, password);
}
@Override public int saveUser(User user) {
String sql="insert into t_user(`username`,`password`,`email`) values(?,?,?)";return update(sql, user.getUsername(), user.getPassword(), user.getEmail());
} } ```
- UserService ```java package service;
import bean.User;
public interface UserService { /**
* 注册用户* @param user*/public void registUser(User user);/*** 登录* @param user* @return*/public User login(User user);/*** 检查用户名是否可用吧* @param username* @return true 存在;false 不存在*/public boolean existsUsername(String username);
}
- UserServiceImpl```javapackage service;import bean.User;import dao.UserDAO;import dao.UserDAOImpl;public class UserServiceImpl implements UserService {private UserDAO userDAO = new UserDAOImpl();@Overridepublic void registUser(User user) {userDAO.saveUser(user);}@Overridepublic User login(User user) {return userDAO.queryUserByUsernameAndPassword(user.getUsername(), user.getPassword());}@Overridepublic boolean existsUsername(String username) {return userDAO.queryUserByUsername(username) != null;}}
第三阶段
- 页面jsp动态化
- html顶部添加 page 指令
- 修改文件后缀名为:.jsp
- 搜索 .html 替换为 .jsp
- form表单数据回显,通过设置request域数据,回显输入的表单数据及错误信息
- BaseServlet抽取
- login + register ∈ users

try {// 获取action业务鉴别字符串,获取相对应的业务,方法反射对象Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);// 调用目标业务(通过反射进行调用 )method.invoke(this, request, response);} catch (Exception e) {e.printStackTrace();}
- BeanUtils 抽取及使用
- 一次性把所有请求参数注入到 JavaBean 中
- 第三方工具类,需要导入jar包
- commons-beanutils-1.8.0
- commons-logging-1.1.1
- 使用BeanUtils类方法实现注入
第四阶段
使用EL表达式修改表单回显${ empty requestScope.msg ? "请输入用户名和密码" : requestScope.msg }
第五阶段
1. 图书模块
1.1 图书模块数据库表
CREATE TABLE `t_book` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(100) DEFAULT NULL,`price` decimal(11,2) DEFAULT NULL,`author` varchar(100) DEFAULT NULL,`sales` int(11) DEFAULT NULL,`stock` int(11) DEFAULT NULL,`img_path` varchar(1000) DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;\INSERT INTO `t_book`(`id`, `name`, `price`, `author`, `sales`, `stock`, `img_path`) VALUES (1, '道德经', 66.00, '老子', 200, 400, 'https://bkimg.cdn.bcebos.com/pic/42166d224f4a20a4933051eb9d529822720ed0f4?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg');INSERT INTO `t_book`(`id`, `name`, `price`, `author`, `sales`, `stock`, `img_path`) VALUES (2, '颜氏家训', 45.00, '颜之推', 102, 300, 'https://bkimg.cdn.bcebos.com/pic/960a304e251f95cad1c80902385f683e6709c93df464?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg');INSERT INTO `t_book`(`id`, `name`, `price`, `author`, `sales`, `stock`, `img_path`) VALUES (3, '一千零一夜', 55.00, '佚名1', 360, 600, 'https://bkimg.cdn.bcebos.com/pic/50da81cb39dbb6fd9aaed6430424ab18962b37d9?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg');INSERT INTO `t_book`(`id`, `name`, `price`, `author`, `sales`, `stock`, `img_path`) VALUES (4, '格林童话', 35.00, '佚名2', 240, 400, 'https://bkimg.cdn.bcebos.com/pic/b3b7d0a20cf431adb6c09cf44036acaf2fdd98e9?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg');INSERT INTO `t_book`(`id`, `name`, `price`, `author`, `sales`, `stock`, `img_path`) VALUES (5, '安徒生童话', 36.00, '佚名3', 230, 400, 'https://bkimg.cdn.bcebos.com/pic/267f9e2f0708283864557860b599a9014c08f16e?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg');INSERT INTO `t_book`(`id`, `name`, `price`, `author`, `sales`, `stock`, `img_path`) VALUES (6, '礼记', 28.00, '佚名4', 220, 400, 'https://bkimg.cdn.bcebos.com/pic/d833c895d143ad4bfcf6c4e18a025aafa40f0632?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg');INSERT INTO `t_book`(`id`, `name`, `price`, `author`, `sales`, `stock`, `img_path`) VALUES (7, '尚书', 29.00, '佚名5', 100, 400, 'https://bkimg.cdn.bcebos.com/pic/95eef01f3a292df52dc95d19ba315c6034a873b0?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg');INSERT INTO `t_book`(`id`, `name`, `price`, `author`, `sales`, `stock`, `img_path`) VALUES (8, '基督山伯爵', 42.00, '佚名6', 260, 400, 'https://bkimg.cdn.bcebos.com/pic/91ef76c6a7efce1b25a63a54a151f3deb58f659b?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg');INSERT INTO `t_book`(`id`, `name`, `price`, `author`, `sales`, `stock`, `img_path`) VALUES (9, '巴黎圣母院', 48.00, '佚名7', 240, 400, 'https://bkimg.cdn.bcebos.com/pic/ae51f3deb48f8c5494eec2f272633af5e0fe9825d19e?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg');INSERT INTO `t_book`(`id`, `name`, `price`, `author`, `sales`, `stock`, `img_path`) VALUES (10, '复活', 53.00, '佚名8', 220, 400, 'https://bkimg.cdn.bcebos.com/pic/1e30e924b899a901bedb4d9c15950a7b0308f5aa?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg');INSERT INTO `t_book`(`id`, `name`, `price`, `author`, `sales`, `stock`, `img_path`) VALUES (11, '小王子', 21.00, '佚名9', 480, 700, 'https://bkimg.cdn.bcebos.com/pic/d000baa1cd11728bf303bdabc6fcc3cec3fd2c08?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg');# 测试select * from t_book;
1.2 图书模块JavaBean
1.3 图书模块DAO和测试DAO
1.4 Service及测试
1.5 Web层和页面联调测试

1.5.1 图书列表
1.5.2 添加图书
- 表单重复提交:
当用户提交完请求,浏览器会记录下最后一次请求的全部信息。当用户刷新F5,会再次请求相同表单,造成重复提交。
1.5.3 删除图书
1.5.4 修改图书
1.5.5 图书分页
- 分页中要连续显示5个页码,当前页码在中间。
1.5.6 价格区间查询
第六阶段
1. 登录—显示用户名
2. 注销用户
2.1 销毁session中用户登录的信息
2.2 重定向到登录页面
3. 表单重复提交—验证码
- 表单重复提交三种情况:
- 提交完表单。服务器使用请求转发来跳转页面。此时,用户按下F5,就会发起最后一次请求,造成表单重复提交问题。解决方案:使用重定向进行跳转。
- 用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器的响应,用户以为提交失败,多点了几次提交也会造成表单重复提交。
- 用户正常提交服务器,服务器无延迟,但是提交完成后,用户回退浏览器。重新提交也会造成表单重复提交。
- 验证码解决表单重复提交的底层原理

谷歌kaptcha 图片验证码的使用
步骤
- 导入kaptcha的jar包
- web.xml 中配置用于生成验证码的servlet程序
<servlet><servlet-name>KaptchaServlet</servlet-name><!-- 直接取得jar包中的路径 --><servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class></servlet><servlet-mapping><servlet-name>KaptchaServlet</servlet-name><url-pattern>/kaptcha.jpg</url-pattern></servlet-mapping>
- web.xml 中配置用于生成验证码的servlet程序
- 在表单中使用img标签展示验证码图片
<img src="${basePath}kaptcha.jpg" width="150px">
- 4. 在服务器获取谷歌生成的验证码和客户端发送过来的验证码进行比较- 5. 切换验证码
第七阶段:购物车

- 修改购物车产品数量

第八阶段:订单
CREATE TABLE t_order (`order_id` VARCHAR ( 50 ) PRIMARY KEY,`create_time` datetime,`price` DECIMAL ( 11, 2 ),`status` INT,`user_id` INT,FOREIGN KEY ( `user_id` ) REFERENCES t_user ( `id` ));CREATE TABLE t_order_item (`id` INT PRIMARY KEY auto_increment,`name` VARCHAR ( 100 ),`count` INT,`price` DECIMAL ( 11, 2 ),`total_price` DECIMAL ( 11, 2 ),`order_id` VARCHAR ( 50 ),FOREIGN KEY ( `order_id` ) REFERENCES t_order ( `order_id` ));
第九阶段:Filter过滤器
1. Filter拦截/pages/manager/所有内容,实现权限检查
2. 使用Filter和ThreadLocal组合管理事务
- ThreadLocal 类
- 解决多线程的数据安全问题
- 当前线程关联一个数据(普通变量、对象、数组、集合)
- 可以像Map一样存取数据,key为当前线程
- 每一个ThreadLocal对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个ThreadLocal对象实例
- 每个ThreadLocal对象实例定义的时候,一般都是static类型
- ThreadLocal保存数据,在线程销毁后,会有JVM虚拟机自动释放

3. 使用Filter过滤器统一给所有Service添加try-catch

4. 将所有异常统一交给tomcat处理,tomcat展示友好提示的页面
web.iml 配置错误页面来处理
附录二:快捷键
- ctrl + alt + t 快速添加“环绕用”(try/catch)
- ctrl + shift + t 快速添加单元测试
- ctrl + R 替换

- mac 下
commend + n,win 下alt + insert
附录三:FAQ
- Tomcat 控制台中文乱码
【conf】-【logging.properties】将UTF-8修改为系统的 GBK - Tomcat doPost 500 错误
删除super.doPost(req, resp);

