Web:全球广域网,也称为万维网(www),能够通过浏览器访问的网站。
JavaWeb:用Java技术来解决相关web互联网领域的技术栈。
B/S架构:Browser/Server(浏览器/服务器)架构模式。其特点是:客户端只需要浏览器,应用程序的逻辑和数据都从存储在服务端。浏览器只需要请求服务器,获取Web资源,服务器把Web资源发送给浏览器即可。
HyperText Transfer Protocol,超文本传输协议,规定了浏览器和服务器之间数据传输的规则。
请求数据分为3部分:
常见的HTTP请求头:
GET请求和POST请求的区别:
响应数据分为3部分:
常见的HTTP响应头:
状态码分类 | 说明 |
---|---|
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 | 客户端需要进行身份验证才能获得网络访问权限 |
创建web项目,导入Servlet依赖坐标
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
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有Web服务器创建,Servlet方法由web服务器调用。
服务器怎么知道servlet中一定有service方法?
因为我们自定义的Servlet,必须实现Servlet接口并复写其方法,而Servlet接口中有service方法
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被创建时执行,只执行一次
void init(ServletConfig config)
提供服务方法,每次Servlet被访问,都会调用该方法
void service(ServletRequest req, ServletResponse res)
销毁方法,当Servlet被销毁时,调用该方法。内存释放或服务器关闭时销毁Servlet
void destroy()
获取ServletConfig对象
ServletConfig getServletConfig()
获取Servlet信息
String getServletInfo()
我们将来开发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想要被访问,必须配置其访问路径(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,所以一般不要用这个
- 当我们的项目中配置了"/*",意味着匹配任意访问路径
优先级:精确路径 > 目录路径 > 扩展名路径 > /* > /
Servlet 3.0版本之后开始支持使用注解 @WebServlet 配置,3.0版本前只支持XML配置文件的方式
步骤:
<servlet>
<servlet-name>demoservlet-name>
<servlet-class>com.itheima.web.servlet.ServletDemoservlet-class>
servlet>
<servlet-mapping>
<servlet-name>demoservlet-name>
<url-pattern>/demourl-pattern>
servlet-mapping>
请求数据分为三部分:
请求行:
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
获取所有参数的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
我们可以将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。
请求转发(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,删除该键值对
请求转发特点:
响应数据分为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.setStatus(302);
response.setHeader("location","资源B的路径");
// 或者直接用下面这种写法
response.sendRedirect("资源B的路径");
重定向特点:
资源路径问题
明确路径是谁使用?
动态获取虚拟目录
String contextPath = request.getContextPath();
response.sendRedirect(contextPath+"/resp2");
通过Response对象获取字符输出流
// 设置流的编码,解决中文乱码问题
response.setContextType("text/html;charset = utf-8");
PrintWriter writer = resp.getWriter(); // 流不需要关闭
写数据
writer.write("你好");
注意:
通过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对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resource.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
问题:
代码优化:
// 封装一个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;
}
}
Java Server Pages,Java服务端页面。一种动态的网页技术,其中既可以定义HTML、JS、CSS等静态内容,还可以定义Java代码的动态内容。即:JSP = HTML + Java
导入JSP坐标
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifictId>jsp-apiartifictId>
<version>2.2version>
<scope>providedscope>
dependency>
创建JSP文件
编写HTML标签和Java代码
hello jsp~
<% Stsyem.out.print("jsp hello~");%>
Expression Language 表达式语言,用于简化JSP页面内的Java代码
主要功能:获取数据
语法:
${brands}
JavaWeb中的四大域对象:
注意:EL表达式获取数据,会依次从这4个域中寻找,直到找到为止
快速入门:
导入坐标
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifictId>
<version>1.2version>
dependency>
<dependency>
<groupId>taglibsgroupId>
<artifactId>standardartifactId>
<version>1.1.2version>
dependency>
在JSP页面上引入JSTL标签库
<%@ taglibs prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
使用
true
false
启用
禁用
${status.count} -
${brand.brandName}
${brand.companyName}
${brand.description}
${i}
会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。
会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自同一浏览器,以便在同一次会话的多次请求间共享数据
HTTP协议是无状态的,每次浏览器向服务器请求时,服务器都会将该请求视为新的请求,因此我们需要会话跟踪技术来实现会话内数据共享。
实现方式:
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存储中文
Cookie默认不能存储中文
解决方式:URL编码
URLEncoder.encode(value, "utf-8"); // 编码
URLDecoder.decode(value, "utf-8"); // 解码
使用
获取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销毁
默认情况下,无操作,30分钟自动销毁
<session-config>
<session-timeout>30session-timeout>
session-config>
调用Session对象的invalidate()方法手动销毁
用户登录
记住用户
如果用户勾选”记住用户”,则下次访问登录页面自动填充用户名密码
如何自动填充用户名和密码呢?
将用户名和密码写入Cookie中,并且持久化存储Cookie,下次访问浏览器会自动携带Cookie
在页面获取Cookie数据后,设置到用户名和密码框中
${cookie.key.value}
何时写Cookie?
用户注册
定义类,实现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可以根据需求,配置不同的拦截资源路径,使用注解:@WebFilter(“路径”)
过滤器链
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接口
在类上添加@WebListener注解
@WebListener
public class ContextLoaderListener implements ServletContextListener{
public void contextInitialized(ServeltContextEvent sce){
// 加载资源
System.out.println("ContextLoaderListener...");
}
public void contextDestroyed(ServletContextEvent sce){
// 释放资源
}
}
与服务器进行数据交换:通过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 对原生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);
})
定义
var 变量名 = {
"key1":value1,
"key2":value2,
...
"name":"zhnagsan",
"age":23,
"addr":["北京","上海","西安"]
};
/*
value的数据类型为:
- 数字(整数或浮点数)
- 字符串(在双引号中)
- 逻辑值(true或false)
- 数组(在方括号中)
- 对象(在花括号中)
- null
*/
获取数据:
变量名.key
使用:
导入坐标
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<versoin>1.2.62versoin>
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对象。
新建HTML页面,引入Vue.js文件
<script src="js/vue.js">script>
在JS代码区域,创建Vue核心对象,进行数据绑定
new Vue({
// el:通过选择器给元素绑定Vue
el:"#app",
data(){
return{
username:""
}
}
});
编写视图
<div id="app">
<input name="username" v-model="username">
{{username}}
div>
指令: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示例
{{addr}}
{{i+1}}--{{addr}}
状态 | 阶段周期 |
---|---|
beforeCreate | 创建前 |
created | 创建后 |
beforeMount | 载入前 |
mounted | 挂载完成 |
beforeUpdate | 更新前 |
updated | 更新后 |
beforeDestroy | 销毁前 |
destroyed | 销毁后 |
引入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核心对象
去官网复制需要的组件代码
自定义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();
}
}
}