JavaWeb简介
- Web:全球广域网,也称为万维网(www),能够通过浏览器访问的网站。
- JavaWeb:用Java技术来解决相关web互联网领域的技术栈。
- B/S架构:Browser/Server(浏览器/服务器)架构模式。其特点是:客户端只需要浏览器,应用程序的逻辑和数据都从存储在服务端。浏览器只需要请求服务器,获取Web资源,服务器把Web资源发送给浏览器即可。
- 好处:易于维护升级。服务端升级后,客户端无需任何部署就能使用到最新的版本
- 静态资源:HTML、css、JavaScript、图片等。负责页面展示
- 动态资源:Servlet、jsp等。负责逻辑处理
- 数据库:负责数据存储
- HTTP协议:定义通信规则
- Web服务器:负责解析HTTP协议,解析请求数据,并发送响应数据
HTTP
概念
HyperText Transfer Protocol,超文本传输协议,规定了浏览器和服务器之间数据传输的规则。
特点
- 基于TCP协议:面向连接,提供可靠的数据传输
- 基于请求-响应模型:一次请求对应一次响应
- http协议是无状态的协议:对于事物处理没有记忆能力,每次请求-响应都是独立的
- 缺点:多次请求间不能共享数据。Java中使用会话技术(cookie、session)来解决这个问题
- 优点:速度快
请求数据格式
请求数据分为3部分:
- 请求行:请求数据的第一行。其中GET表示请求方式,/表示请求资源路径,HTTP/1.1表示协议版本
- 请求头:第二行开始,格式为 key: value形式
- 请求体:POST请求方式特有的,在请求数据的最后一部分,注意要与请求头之间空一行,用于存放请求参数
常见的HTTP请求头:
- Host:表示请求的主机名
- User-Agent:浏览器版本,例如Chrome浏览器的标识类似Mozilla/5.0 Chrome/79
- Accept:表示浏览器能接收的资源类型,如text/*,image/*或者*/*表示所有;
- Accept-Language:表示浏览器偏好的语言,服务器可以据此返回不同语言的网页;
- Accept-Ecoding:表示浏览器可以支持的压缩类型,例如gzip,deflate等。
GET请求和POST请求的区别:
- GET请求请求参数在请求行中,没有请求体。POST请求请求参数在请求体中
- GET请求请求参数有大小限制,POST没有
响应数据格式
响应数据分为3部分:
- 响应行:响应数据的第一行。其中HTTP/1.1表示协议版本,200表示响应状态码,OK表示状态码描述
- 响应头:第二行开始,格式为key: value形式
- 响应体:最后一部分,存放响应数据
常见的HTTP响应头:
- Content-Type:表示该响应内容的类型,例如text/html,image/jpeg;
- Content-Length:表示该响应内容的长度(字节数);
- Content-Encoding:表示该响应压缩算法,例如gzip;
- Cache-Control:指示客户端应如何缓存,例如max-age=300表示可以最多缓存300秒。
状态码大类
状态码分类 | 说明 |
1xx | 响应中——临时状态码,表示请求已经接受,告诉客户端应该继续请求或者如果他已经完成则忽略它 |
2xx | 成功——表示请求已经被成功接收,处理已完成 |
3xx | 重定向——重定向到其它地方:他让客户端再发起一个请求以完成整个处理 |
4xx | 客户端错误——处理发生错误,责任在客户端,如:客户端的请求一个不存在的资源,客户端未被授权,禁止访问等 |
5xx | 服务器端错误——处理发生错误,责任在服务器,如:服务器端抛出异常,路由出错,http版本不支持等 |
常见的响应状态码
状态码 | 英文描述 | 解释 |
200 | OK | 客户端请求成功,即处理成功,这是我们最想看到的状态码 |
302 | Found | 指示所请示的资源已移动到由location响应头给定的URL,浏览器会自动重新访问到这个页面 |
304 | Not Modified | 告诉客户端,你请求的资源至上次取得之后,服务端并未更改,你直接用你本地缓存吧。隐式重定向 |
400 | Bad Request | 客户端请求有语法错误,不能被服务器所理解 |
403 | Forbidden | 服务器收到请求,但是拒绝提供服务,比如:没有权限访问相关资源 |
404 | Not Found | 请求资源不存在,一般是URL输入有误,或者网站资源被删除了 |
428 | Precondition Request | 服务器要求有条件的请求,告诉客户端要想访问该资源,必须携带特定的请求头 |
429 | Too Many Request | 太多请求,可以限制客户端请求某个资源的数量,配合Retry-After(多长时间后可以请求)响应头一起使用 |
431 | Request Header Fields Too Large | 请求头太大,服务器不愿意处理请求,因为他的头部字段太大。请求可以在减少请求头域的大小后重新提交 |
405 | Method Not Allowed | 请求方式有误,比如应该使用GET请求方式的资源,用了POST |
500 | Internal Server Error | 服务器发生不可预期的错误 |
503 | Service Unavailable | 服务器尚未准备好处理处理请求,服务器刚启动,还未初始化好 |
511 | Network Authentication Required | 客户端需要进行身份验证才能获得网络访问权限 |
Servlet
- Servlet是Java提供的一门动态web资源开发技术
- Servlet是JavaEE规范之一,其实就是一个接口,将来我们需要定义Servlet类实现Servlet接口,并由web服务器运行Servlet
快速入门
- 创建web项目,导入Servlet依赖坐标
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
- 创建:定义一个类,实现Servlet接口,并重写接口中所有方法
public class ServletDemo1 implements Servlet{
public void service(){
};
}
- 配置:在类上使用@WebServlet 注解,配置该Servlet的访问路径
@WebServlet("/demo1")
public class ServeltDemo1 implements Servlet{
}
- 访问:启动Tomcat,浏览器输入URL访问该Servlet
http://localhost:8080/web-demo/demo1
Servlet执行流程
- Servlet由谁创建?Servlet方法由谁调用?
Servlet有Web服务器创建,Servlet方法由web服务器调用。 - 服务器怎么知道servlet中一定有service方法?
因为我们自定义的Servlet,必须实现Servlet接口并复写其方法,而Servlet接口中有service方法
Servlet生命周期
Servlet运行在Servlet容器(web服务器)中,其生命周期由容器来管理,分为4个阶段:
- 加载和实例化:默认情况下,当Servlet第一次被访问时,由容器创建Servlet对象
@WebServlet(urlPatterns = "/demo", loadOnStartup = 1)
/*
设置loadOnStartup参数,改变Servlet对象创建的时间
- 负整数:第一次被访问时创建Servlet对象,默认
- 0或正整数:服务器启动时创建Servlet对象,数字越小优先级越高
*/
- 初始化:在Servlet实例化之后,Servlet容器将调用Servlet的 init() 方法初始化这个对象,完成一些如加载配置文件、创建连接等初始化的工作。该方法只调用一次
- 请求处理:每次请求Servlet时,Servlet容器都会调用Servlet的 service() 方法对请求进行处理
- 服务终止:当需要释放内存或者容器关闭时,容器就会调用Servlet实例的 destroy() 方法完成资源的释放。当 destroy() 方法调用后,容器会释放这个Servlet实例,该实例随后会被Java的垃圾回收器所回收
Servlet方法介绍
- 初始化方法,在Servlet被创建时执行,只执行一次
void init(ServletConfig config)
- 提供服务方法,每次Servlet被访问,都会调用该方法
void service(ServletRequest req, ServletResponse res)
- 销毁方法,当Servlet被销毁时,调用该方法。内存释放或服务器关闭时销毁Servlet
void destroy()
- 获取ServletConfig对象
ServletConfig getServletConfig()
- 获取Servlet信息
String getServletInfo()
Servlet体系结构
我们将来开发B/S架构的web项目,都是针对HTTP协议,所以我们自定义Servlet,会继承HttpServlet。
@WebServlet("/demo")
public class ServletDemo extends HttpServlet{
@override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
System.out.println("get...");
}
}
@override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
System.out.println("post...");
}
}
一般的Servlet类需要在service()方法中根据请求方式的不同(因为不同的请求方式的参数位置不一样),分别处理请求。
@override
public void service(ServletRequest req, ServletResponse resp)throws ServletException, IOException(){
// 根据请求方式的不同,进行分别的处理
// 需要将ServeletRequest对象强转为HttpServletRequest对象这样才能获取到请求方式
HttpServletRequest request = (HttpServletRequest) req;
// 1.获取请求方式
String method = request.getMethod();
// 2.判断
if("GET".equals(method)){
// get方式的请求逻辑
}else if("POST".equals(method)){
// post方式的请求逻辑
}
}
HttpServlet类都将上面这些代码封装好了,我们不需要再写代码判断请求方式,只需要重写doGet()方法和doPost()方法就好了。
Servlet urlPattern配置
Servlet想要被访问,必须配置其访问路径(urlParttern)
- 一个Servlet,可以配置多个urlPattern
@WebServlet(urlPatterns = {"/demo1",{"/demo2"}})
- urlPattern配置规则
- 精确匹配
配置路径:@WebServlet("/user/select")
访问路径:localhost:8080/web-demo/user/select
- 目录匹配
配置路径:@WebServlet("/user/*")
访问路径:localhost:8080/web-demo/user/aaa
localhost:8080/web-demo/user/bbb
- 扩展名匹配
配置路径:@WebServlet("*.do")
访问路径:localhost:8080/web-demo/aaa.do
localhost:8080/web-demo/bbb.do
- 任意匹配
配置路径:@WebServlet("/")
@WebServlet("/*")
访问路径:localhost:8080/web-demo/hello
localhost:8080/web-demo/aaa
/ 和 /* 的区别:
- 当我们的项目中的Servlet配置了"/",会覆盖掉Tomcat中的DefaultServlet,当其他的url-pattern都匹配不上时都会走这个Servlet,所以一般不要用这个
- 当我们的项目中配置了"/*",意味着匹配任意访问路径
优先级:精确路径 > 目录路径 > 扩展名路径 > /* > /
XML配置方式编写Servlet
Servlet 3.0版本之后开始支持使用注解 @WebServlet 配置,3.0版本前只支持XML配置文件的方式
步骤:
- 编写Servlet类
- 在web.xml中配置该Servlet
<!-- 配置Servlet全类名:servlet-class -->
<servlet>
<servlet-name>demo</servlet-name>
<servlet-class>com.itheima.web.servlet.ServletDemo</servlet-class>
</servlet>
<!-- 配置访问路径 -->
<servlet-mapping>
<servlet-name>demo</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
Request & Response
- Request:获取请求数据
- Response:设置响应参数
Request继承体系
- Tomcat需要解析请求数据,封装为request对象,并创建request对象传递到service方法中
- 使用request对象,查阅JavaEE API文档的HttpServletRequest接口。
Request获取请求参数
请求数据分为三部分:
- 请求行:
GET/request-demo/req1?username=zhangsan HTTP/1.1
request对象方法:
String getMethod(); // 获取请求方式
String getContextPath(); // 获取虚拟目录(项目访问路径):request-demo
StringBuffer getRequestURL(); // 获取URL(统一资源定位符):http://localhost:8080/request-demo/req1
String getRequestURI(); // 获取URL(统一资源标识符):/request-demo/req1
String getQueryString(); // 获取请求参数(GET方式):username=zhangsan&password=123
- 请求头
User-Agent:Mozilla/5.0 Chrome/91.0.4472.106
request对象方法:
String getHander(String name); // 根据请求头名称获取值
- 请求体
username=zhangsan&password=123
request对象方法
ServletInputStream getInputStream(); // 获取字节输入流
BufferReader getReader(); // 获取字符输入流,post方式获取请求参数
GET、POST通用的获取请求参数的方式:
Request 会将获取到的请求参数封装为一个Map<String, String[]> 集合
- 获取所有参数的map集合
Map<String, String[]> getParameterMap(); //获取所有参数map集合
- 根据key获取参数值,数组
String[] getParameterValues(String name); // 根据键名获取参数值(数组)
- 根据key获取单个参数值
String getParameter(String name); // 根据键名获取参数值(单个值)
实际开发中可以利用这种通用的方法简化代码,让doPost()方法直接调用doGet()方法来获取请求参数。实际上在底层这几个通用的方法还是根据具体的请求方式来选择调用getQueryString()和getReader()完成参数的获取。
解决请求参数是中文时的乱码问题
- post方法:获取请求参数时使用的是getReader()方法获取字符输入流,因此我们需要设置字符输入流的编码
request.setCharacterEncoding('UTF-8');
- get方法:使用getQueryString()方法直接获取字符串来获取请求参数。浏览器url是不支持中文的,所以对于请求参数中的中文浏览器都会对其进行URL编码,编码方式为utf-8,然后再发送到Tomcat服务器通过服务器解码,因此我们需要设置Tomcat的URL编码的解码方式也为uft-8
- URL编码
- 将字符串按照编码方式转为二进制
- 每个字节转为2个16进制数并在前边加上%
我们可以将Tomcat生成的乱码数据转换成字节数据,在转换成utf-8的格式
// 获取请求参数
String username = request.getParameter("username");
// 转换为字节数据
byte[] bytes = username.getBytes("ISO-8859-1");
// 将字节数据转为字符串
username = new String(bytes, "utf-8");
注意:Tomcat 8.0 之后,已经将get请求乱码问题解决了,设置默认的解码方式为utf-8。
Request请求转发
请求转发(forward):一种在服务器内部的资源跳转方式
资源A处理了一部分之后转发给资源B接着处理
实现方式:
request.getRequestDispatcher("资源B路径").forward(request,response);
请求转发资源间共享数据:使用Request对象
void setAttribute(String name, Object obj); // 存储数据到request域中
Object getAttribute(String name); // 根据key,获取值
void removeAttribute(String name); // 根据key,删除该键值对
请求转发特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器的内部资源
- 一次请求,可以在转发的资源间使用request共享数据
Response设置响应数据功能介绍
响应数据分为3部分:
- 响应行:
HTTP/1.2 200 OK
void setStatus(int sc); // 设置响应状态码
- 响应头:
Content-Type:text/html
void setHeader(String name, String value); // 设置响应头键值对
- 响应体:
<html><head></head><body></body></html>
PrintWriter getWriter(); // 获取字符输出流
ServletOutputStream getOutputStream(); // 获取字节输出流
Response完成重定向
- 重定向(Redirect):一种资源跳转的方式
- 实现方式:
response.setStatus(302);
response.setHeader("location","资源B的路径");
// 或者直接用下面这种写法
response.sendRedirect("资源B的路径");
重定向特点:
- 浏览器地址栏路径发生变化
- 可以重定向到任意位置的资源(服务器内部、外部均可)
- 两次请求,不能在多个资源使用功能request共享数据
资源路径问题
- 明确路径是谁使用?
- 浏览器使用:需要加载虚拟目录(项目访问路径)
- 服务端使用:不需要加虚拟目录
- 动态获取虚拟目录
String contextPath = request.getContextPath();
response.sendRedirect(contextPath+"/resp2");
Response响应字符数据
- 通过Response对象获取字符输出流
// 设置流的编码,解决中文乱码问题
response.setContextType("text/html;charset = utf-8");
PrintWriter writer = resp.getWriter(); // 流不需要关闭
- 写数据
writer.write("你好");
注意:
- 该流不需要关闭,随着响应结束,response对象销毁,有服务器关闭
- 中文数据乱码:原因是通过response获取的字符输出流默认编码是:ISO-8859-1
Response响应字节数据
- 通过Response对象获取字节输出流
ServletOutputStream outputStream = resp.getOutputStream();
- 写数据
outputStraeam.write(字节数据);
例:
// 1.读取文件
FileInputStream fis = new FileInputStream("d://a.jpg");
// 2.获取request字节输出流,这个流不需要关闭
ServletOutputStream os = response.getOutputStream();
// 3.完成流的copy
/* 传统写法:
byte[] buff = new byte[1024];
int len = 0;
while((len = fis.read(buff))!=-1){
os.write(buff,0,len);
}
*/
// 利用common-io工具类
IOUtils.copy(fis,os);
fis.close
SqlSessionFactory工具类抽取
// 创建SQLSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resource.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
问题:
- 代码重复
- SQLSessionFactory工厂只创建一次,不要重复创建,否则很浪费资源
代码优化:
// 封装一个SqlSessionFactoryUtils工具类
public class SqlSessionFactoryUtils{
private static SqlSessionFactory sqlSessionFactory;
static{
// 静态代码块会随着类的加载自动执行,并且只执行一次
try{
String resource = "mybatis-config.xml";
InputStream inputStream = Resource.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch(IOException e){
e.printStackTrace();
}
}
public static SqlSessionFactory getSqlSessionFactory(){
return sqlSessionFactory;
}
}
JSP——Java服务端页面
概念
Java Server Pages,Java服务端页面。一种动态的网页技术,其中既可以定义HTML、JS、CSS等静态内容,还可以定义Java代码的动态内容。即:JSP = HTML + Java
- 作用:简化开发,避免了在Servlet中直接输出HTML标签
JSP快速入门
- 导入JSP坐标
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifictId>jsp-api</artifictId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
- 创建JSP文件
- 编写HTML标签和Java代码
<body>
<h1>
hello jsp~
</h1>
<% Stsyem.out.print("jsp hello~");%>
</body>
JSP原理
- JSP本质上就是一个Servlet
- JSP在被访问时,由JSP容器(Tomcat)将其转换为Java文件(Servlet),再由JSP容器(Tomcat)将其编译,最终对外提供服务的其实就是这个字节码文件。
JSP脚本
- 用于在JSP页面内定义Java代码
- JSP脚本分类:
- <%…%>:内容会直接放到_jspService()方法中
- <%=…%>:内容会放到out.print()中,作为out.print()的参数
- <%!..%>:内容会放到_jspService()方法之外,被类直接包含,一般用于定义成员变量和成员方法
- JSP缺点:
- 书写麻烦,特别是复杂的页面
- 阅读麻烦
- 复杂度高:运行需要依赖各种环境,JRE,JSP容器,JavaEE等
- 占内存和磁盘:JSP会自动生成.java和.class文件占磁盘,运行的是.class文件占内存
- 调试困难:出错后,需要找到自动生成的.java文件进行调试
- 不利于团队协作:前端人员不会Java,后端人员不精HTML
EL表达式
Expression Language 表达式语言,用于简化JSP页面内的Java代码
- 主要功能:获取数据
- 语法:
<!-- 获取域中存储的key为brands的数据 -->
${brands}
- JavaWeb中的四大域对象:
- page:当前页面有效
- request:当前请求有效
- session:当前会话有效
- application:当前应用有效
注意:EL表达式获取数据,会依次从这4个域中寻找,直到找到为止
JSTL标签
- JSP标准标签库(Jsp Standarded Tag Liberty),使用标签取代JSP页面上的Java代码。
快速入门:
- 导入坐标
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifictId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
- 在JSP页面上引入JSTL标签库
<%@ taglibs prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- 使用
<!-- c:if 用来完成逻辑判断,替换Java中的is-else -->
<c:if test="true">
<h1>true</h1>
</c:if>
<c:if test="false">
<h1>false</h1>
</c:if>
<!-- 例 -->
<c:if test="${status == 1}">
<h1>启用</h1>
</c:if>
<c:if test="${status == 0}">
<h1>禁用</h1>
</c:if>
<!-- c:forEach 相当于java中的for循环
- items:被遍历的容器
- var:每次遍历产生的临时变量
- varStatus:遍历状态对象,status.index从0开始,status.count从1开始
-->
<c:forEach items="${brands}" var="brand" varStatus="status">
<tr align="center">
<!-- 注意这里写的id是属性名称
EL表达式中这样写会自动调用对象对应的get方法来获取属性
-->
<!--<tb>${brand.id}</tb>-->
<tb>${status.count}</tb>-
<tb>${brand.brandName}</tb>
<tb>${brand.companyName}</tb>
<tb>${brand.description}</tb>
</tr>
</c:forEach>
<!-- 普通for循环 -->
<c:forEach begin="0" end="10" step="1" var="i">
${i}
</c:forEach>
MVC模式和三层架构
- MVC模式是一种分层开发的模式,其中
- M:Model,业务模型,处理业务
- V:View,视图,界面展示
- C:Controller,控制器,处理请求,调用模型和视图
- MVC好处:
- 职责单一,互不影响
- 有利于分工协作
- 有利于组件重用
- 三层架构
- 数据访问层:对数据库的CRUD基本操作
- 业务逻辑层:对业务逻辑进行封装,组合数据访问层层中基本功能,形成复杂的业务逻辑功能
- 表现层:接收请求,封装数据,调用业务逻辑层,响应数据
会话跟踪技术——Cookie&Session
- 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。
- 会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自同一浏览器,以便在同一次会话的多次请求间共享数据
- HTTP协议是无状态的,每次浏览器向服务器请求时,服务器都会将该请求视为新的请求,因此我们需要会话跟踪技术来实现会话内数据共享。
- 实现方式:
- 客户端会话跟踪技术:Cookie
- 服务端会话跟踪技术:Session
Cookie基本使用
Cookie:客户端会话技术,将数据保存到客户端,以后每次请求都携带Cookie数据进行访问
Cookie基本使用
- 创建Cookie对象,设置数据
Cookie cookie = new Cookie("key","value");
- 发送Cookie到客户端:使用response对象
response.addCookie(cookie);
- 获取客户端携带的所有Cookie:使用request对象
Cookie[] cookies = request.getCookies();
- 遍历数组,获取每个Cookie对象:for
- 使用Cookie对象方法获取数据
cookie.getName();
cookie.getValue();
Cookie原理
- Cookie的实现是基于http协议的
- 响应头:set-cookie(发送cookie)
- 请求头:cookie(获取cookie)
Cookie使用细节
- Cookie存活时间
- 默认情况下,Cookie存储在浏览器内存中,当浏览器关闭,内存释放,则Cookie被销毁
- setMaxAge(int seconds):设置Cookie存活时间
- 正数:Cookie写入浏览器所在电脑的硬盘,持久化存储,到时间自动删除
- 负数:默认值,Cookie在当前浏览器内存中,当浏览器关闭,则Cookie被销毁
- 零:删除对应Cookie
- Cookie存储中文
- Cookie默认不能存储中文
- 解决方式:URL编码
URLEncoder.encode(value, "utf-8"); // 编码
URLDecoder.decode(value, "utf-8"); // 解码
Session基本使用
- 服务端会话跟踪技术:将数据保存到服务端
- JavaEE提供HttpSession接口,来实现一次会话的多次请求间数据共享功能
- 使用
- 获取Session对象
HttpSession session = request.getSession();
- Session对象功能
void setAttribute(String name, Object o); // 存储数据到session域中
Object getAttribute(String name); // 根据key获取值
void removeAttribute(String name); // 根据key删除该键值对
Session原理
- Session是基于Cookie实现的
- Tomcat默认会将Session的id作为一个Cookie数据发送给浏览器
Session使用细节
- Session钝化、活化
- 服务器重启后,Session中的数据是否还在?答案是:在
- 钝化:在服务器正常关闭之后,Tomcat会自动将Session数据写入到硬盘的文件中
- 活化:再次启动服务器后,从文件中加载数据到Session中
- 注意:当浏览器关闭一次会话就结束了,再重启将不能再获取到同一个Session对象
- Session销毁
- 默认情况下,无操作,30分钟自动销毁
<session-config>
<session-timeout>30</session-timeout>
</session-config>
- 调用Session对象的invalidate()方法手动销毁
Cookie和Session对比
- Cookie和Session都是来完成一次会话内多次请求间数据共享的
- 区别:
- 存储位置:Cookie是将数据存储在客户端,Session是将数据存储在服务端
- 安全性:Cookie不安全,Session安全
- 数据大小:Cookie最大3KB,Session没有大小限制
- 存储时间:Cookie可以长时间存储,Session默认30分钟
- 服务器性能:Cookie不占服务器资源,Session占用服务器资源
案例:用户登录注册
- 用户登录
- 三层架构
- 详细代码
- 记住用户
- 如果用户勾选”记住用户”,则下次访问登录页面自动填充用户名密码
- 如何自动填充用户名和密码呢?
- 将用户名和密码写入Cookie中,并且持久化存储Cookie,下次访问浏览器会自动携带Cookie
- 在页面获取Cookie数据后,设置到用户名和密码框中
${cookie.key.value} <!-- key指存储在cookie中的键的名称 -->
- 何时写Cookie?
- 登陆成功
- 用户勾选记住用户复选框
- 用户注册
- 注册功能:保存用户信息到数据库
- 验证码功能:
- 展示验证码:展示验证码图片,可以点击切换图片
- 验证码就是使用Java代码生成的一张图片
- 验证码作用:防止机器自动注册,攻击服务器
- 校验验证码:验证码填写不正确,则注册失败
Filter
概念
- Filter表示过滤器,是JavaWeb三大组件(Servlet,Filter,Listener)之一。
- 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
- 过滤器一般完成一些通用的操作,比如:权限控制、统一编码处理、敏感字符处理等等
Filter快速入门
- 定义类,实现Filter接口,并重写其所有方法
public class FilterDemo implements Filter{
public void init(FilterConfig filterConfig) throw ServletException{
}
public void doFilter(ServletRequest request, ServletResponse response) throw IOException{
}
public void destroy(){
}
}
- 配置Filter拦截资源的路径:在类上定义@WebFilter 注解
@WebFilter("/*")
public class FilterDemo implements Filter{
……
}
- 在doFilter方法中输出一句话,并放行
public void doFilter(ServletRequest request, ServletResponse response)throw IOException{
// 1.放行前,对request数据进行处理
System.out.println("filter放行前……");
// 2.放行,访问资源……response携带数据
chain.doFilter(request,response);
// 3.放行后,对response数据进行处理
System.out.println("filter放行后……");
}
Filter执行流程
放行后访问对应资源,资源访问完成后,还会回到Filter中,并且是执行放行后的逻辑。即:执行放行前逻辑 → 放行 → 访问资源 → 执行放行后逻辑
Filter使用细节
- Filter拦截路径配置
Filter可以根据需求,配置不同的拦截资源路径,使用注解:@WebFilter(“路径”)
- 拦截具体的资源:/index.jsp:只有访问index.jsp时才会被拦截
- 目录拦截:/user/*:访问/user下的所有资源都会被拦截
- 拦截所有:/*:访问所有资源,都会被拦截
- 过滤器链
- 一个Web应用,可以配置多个过滤器,这多个过滤器称为过滤器链
- 注解配置的Filter,执行优先级按照过滤器类名(字符串)的自然排序
案例:登录验证
- 需求:访问服务器资源时,需要先进行登录验证,如果没有登录,则自动跳转到登录页面
Listener
概念
- Listener表示监听器,是JavaWeb三大组件(Servlet、Filter、Listener)之一
- 监听器就是在application,session,request三个对象创建、销毁或者往其中添加、修改、删除属性时自动执行代码的功能组件
- Listener分类:JavaWeb中提供了8个监听器
监听器分类 | 监听器名称 | 作用 |
ServletContext监听 | ServletContextListener | 用于对ServletContext对象进行监听(创建、销毁) |
ServletContextAttributeListener | 对ServletContext对象中属性的监听(增删改属性) | |
Session监听 | HttpSessionListener | 对Session对象的整体状态的监听(创建、销毁) |
HttpSessionAttributeListener | 对Session对象中的属性监听(增删改属性) | |
HttpSessionBindingListener | 监听对象于Session的绑定和解除 | |
HttpSessionActivationListener | 对Session数据的钝化和活化的监听 | |
Request监听 | ServletRequestListener | 对Request对象进行监听(创建、销毁) |
ServletRequestAttributeListener | 对Request对象中属性的监听(增删改属性) |
ServletContextListener使用
- 定义类,实现ServletContextListener接口
- 在类上添加@WebListener注解
@WebListener
public class ContextLoaderListener implements ServletContextListener{
public void contextInitialized(ServeltContextEvent sce){
// 加载资源
System.out.println("ContextLoaderListener...");
}
public void contextDestroyed(ServletContextEvent sce){
// 释放资源
}
}
Ajax
概念
- AJAX(Asynchronous JavaScript And XML):异步的JavaScript和XML
作用
- 与服务器进行数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据
- 使用了Ajax和服务器进行通信,就可以使用HTML + Ajax来替换JSP页面了
- 异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想、用户名是否可用校验,等等……
异步和同步
Ajax快速入门
- 编写AjaxServlet,并使用response输出字符串
- 创建XMLHttpRequest对象:用于和服务器交换数据
var xmlhttp;
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
- 向服务器发送请求
xmlhttp.open("GET","url");
xmlhttp.send(); // 发送请求
- 获取服务器响应数据
/*
readyState 保存了XMLHttpRequest的状态
- 0:请求未初始化
- 1:服务器连接已建立
- 2:请求已接收
- 3:正在处理请求
- 4:请求已完成且响应已就绪
status
- 200:"OK"
- 403:"Forbidden"
- 404:"Page not found"
statusText 返回状态文本(例如"OK"或"Not Found")
*/
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
alert(xmlhttp.responseText);
}
}
案例:验证用户名是否存在
- 需求:在完成用户注册时,当用户名输入框失去焦点时,校验用户名是否在数据库已存在
Axios异步框架
- Axios 对原生Ajax进行封装,简化书写
- 官网:http://www.axios-http.cn
- Axois快速入门:
- 引入axios的js文件
<script src="js/axios-0.18.0.js"></script>
- 使用axios发送请求,并获取响应结果
axios({
method:"get",
url:"http://localhost:8080/ajax-demo/aJAXDemo?username=zhangsan"
}).then(function(resp){
alert(resp.data);
})
axios({
method:"post",
url:"http://localhost:8080/ajax-demo/aJAXDemo",
data:"username=zhangsan"
}).then(function(resp){
alert(resp.data);
})
JSON
概念
- JavaScript Object Notation。JavaScript对象表示法
- 由于其语法简单,层次结构鲜明,现多用于作为数据载体,在网络中进行数据传输
JSON基础语法
定义
var 变量名 = {
"key1":value1,
"key2":value2,
...
"name":"zhnagsan",
"age":23,
"addr":["北京","上海","西安"]
};
/*
value的数据类型为:
- 数字(整数或浮点数)
- 字符串(在双引号中)
- 逻辑值(true或false)
- 数组(在方括号中)
- 对象(在花括号中)
- null
*/
获取数据:
变量名.key
JSON数据和Java对象转换
- Fastjson是阿里巴巴提供的一个Java语言编写的高性能功能完善的JSON库,是目前Java语言中最快的JSON库,可以实现Java对象和JSON字符串的相互转换。
- 请求数据:JSON字符串转为Java对象
- 响应数据:Java对象转为JSON字符串
- 使用:
- 导入坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<versoin>1.2.62</versoin>
</dependency>
- Java对象转JSON
String jsonStr = JSON.toJSONString(obj);
- JSON字符串转Java对象
User user = JSON.parseObject(jsonStr, User.class);
注意:获取JSON数据不能使用request.getParameter(),而是使用request.getReader().readLine(),然后将获取到的JSON字符使用parseObject(param, 类名.calss)转换为相应的Java对象。
Vue
- Vue是一套前端框架,免除原生JavaScript中的DOM操作,简化书写
- 基于MVVM(Model-View-ViewModel)思想,实现数据的双向绑定,将编程的关注点放在
Vue快速入门
- 新建HTML页面,引入Vue.js文件
<script src="js/vue.js"></script>
- 在JS代码区域,创建Vue核心对象,进行数据绑定
new Vue({
// el:通过选择器给元素绑定Vue
el:"#app",
data(){
return{
username:""
}
}
});
- 编写视图
<div id="app">
<!-- v-model要和前面Vue里面写的模型名字一样 -->
<input name="username" v-model="username">
<!-- {{差值表达式}} -->
{{username}}
</div>
Vue常用指令
- 指令:HTML标签上带有v-前缀的特殊属性,不同指令具有不同含义。例如:v-if,v-for等
- 常用指令
指令 | 作用 |
v-bind | 为HTML标签绑定属性值,如设置href,css样式等。简化只写:,如:href="" |
v-model | 在表单元素上创建双向数据绑定 |
v-on | 为HTML标签帮绑定事件,简化写@,如@click="" |
v-if | |
v-else | 条件性的渲染元素,判断为true时渲染,否则不渲染 |
v-else-if | |
v-show | 根据条件展示某元素,和v-if的区别在于切换的是display属性的值 |
v-for | 列表渲染,遍历容器的元素或者对象的属性 |
- v-for示例
<div v-for="addr in addrs">
{{addr}}<br>
</div>
<!-- 加索引 -->
<div v-for="(addr,i) in addrs">
<!-- i表示索引,从0开始 -->
{{i+1}}--{{addr}}<br>
</div>
Vue生命周期
- 生命周期的八个阶段:每触发一个生命周期事件,会自动执行一个生命周期方法(钩子)
状态 | 阶段周期 |
beforeCreate | 创建前 |
created | 创建后 |
beforeMount | 载入前 |
mounted | 挂载完成 |
beforeUpdate | 更新前 |
updated | 更新后 |
beforeDestroy | 销毁前 |
destroyed | 销毁后 |
- mounted:挂载完成,Vue初始化成功,HTML页面渲染成功。
- 发送异步请求,加载数据
Element
- Element:是饿了么公司前端开发团队提供的一套基于Vue的网站组件库,用于快速构建网页
- 组件:组成网页的部件,例如:超链接、按钮、图片、表格等等
快速入门
- 引入Element的css、js文件和Vue.js
<script src="vue.js"></script>
<script src="element-ui/lib/index.js"></script>
<link rel="stylesheet" href="element-ui/lib/theme-chalk/index.css">
- 创建Vue核心对象
<script>
new Vue({
el:"#app"
})
</script>
- 去官网复制需要的组件代码
Element布局
- Element有两种布局方式:
- Layout布局:通过基础的24分栏,迅速便捷地创建布局
- Container布局容器:用于布局的容器组件,方便快速搭建页面的基本结构
Servlet代码优化
- Web层的Servlet个数太多了,不利于管理和编写
- 将Servlet进行归类,对于同一个实体的操作方法,写到一个Servlet中。比如:BrandServlet、UserServlet
自定义Servlet,使用请求路径进行方法分发,替换HttpServlet的根据请求方法进行方法分发。
/*
替换HttpServlet,根据请求的最后一段路径来进行方法分发
*/
public class BaseServlet extends HttpServlet{
// 根据请求的最后一段路径来进行方法分发
@override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
//1.获取请求路径
String uri = req.getRequesetURI(); // /brand-case/brand/selectAll
//获取最后一段路径,即方法名
int index = uri.lastIndexOf('/');
String methodName = uri.substring(index + 1);
//2.执行方法
//2.1 获取BrandServlet字节码对象 Class
//谁调用我(this所在的方法),我(this)代表谁
Class<? extends BaseServlet> cls = this.getClass();
//2.2 获取方法 Method对象
try{
Method method = cls.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//2.3 执行方法
method.invoke(this, req, resp);
}catch(NoSuchMethodException e){
e.printStackTrace();
}catch(IllegalAccessException e){
e.printStackTrace();
}catch(InvocationTargetException e){
e.printStackTrace();
}
}
}