1. HTTP协议
在网络上传输html时的协议,用于B-C的通信
http1.0:一次只能获得一个Web资源,获取后就断开链接
http1.1:持久连接,可以获得多个web资源
浏览器请求过程:
-
与服务器建立TCP连接(80端口)
-
发送HTTP请求
-
收取HTTP响应,然后把网页在浏览器中显示出来
https:443端口
浏览器发送的HTTP:
GET / HTTP/1.1 Host: www.sina.com.cn User-Agent: Mozilla/5.0 xxx Accept: */* Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8
其中,第一行表示使用GET
请求获取路径为/
的资源,并使用HTTP/1.1
协议,从第二行开始,每行都是以Header: Value
形式表示的HTTP头,比较常用的HTTP Header包括:
-
Host: 表示请求的主机名,因为一个服务器上可能运行着多个网站,因此,Host表示浏览器正在请求的域名;
-
User-Agent: 标识客户端本身,例如Chrome浏览器的标识类似
Mozilla/5.0 ... Chrome/79
,IE浏览器的标识类似Mozilla/5.0 (Windows NT ...) like Gecko
; -
Accept:表示浏览器能接收的资源类型,如
text/*
,image/*
或者*/*
表示所有; -
Accept-Language:表示浏览器偏好的语言,服务器可以据此返回不同语言的网页;
-
Accept-Encoding:表示浏览器可以支持的压缩类型,例如
gzip, deflate, br
。
Get方法:能够携带参数少,不安全(URL中会携带参数),但是高效
Post方法:携带的参数无限制,安全但不高效
服务器的响应:
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 21932 Content-Encoding: gzip Cache-Control: max-age=300 <html>...网页数据...
服务器响应的第一行总是版本号+空格+数字+空格+文本,数字表示响应代码,其中2xx
表示成功,3xx
表示重定向,4xx
表示客户端引发的错误,5xx
表示服务器端引发的错误。数字是给程序识别,文本则是给开发者调试使用的。常见的响应代码有:
-
200 OK:表示成功;
-
301 Moved Permanently:表示该URL已经永久重定向;
-
302 Found:表示该URL需要临时重定向;
-
304 Not Modified:表示该资源没有修改,客户端可以使用本地缓存的版本;
-
400 Bad Request:表示客户端发送了一个错误的请求,例如参数无效;
-
401 Unauthorized:表示客户端因为身份未验证而不允许访问该URL;
-
403 Forbidden:表示服务器因为权限问题拒绝了客户端的请求;
-
404 Not Found:表示客户端请求了一个不存在的资源;
-
500 Internal Server Error:表示服务器处理时内部出错,例如因为无法连接数据库;
-
503 Service Unavailable:表示服务器此刻暂时无法处理请求。
从第二行开始,服务器每一行均返回一个HTTP头。服务器经常返回的HTTP Header包括:
-
Content-Type:表示该响应内容的类型,例如
text/html
,image/jpeg
; -
Content-Length:表示该响应内容的长度(字节数);
-
Content-Encoding:表示该响应压缩算法,例如
gzip
; -
Cache-Control:指示客户端应如何缓存,例如
max-age=300
表示可以最多缓存300秒。
HTTP请求和响应都由HTTP Header和HTTP Body构成,其中HTTP Header每行都以\r\n
结束。如果遇到两个连续的\r\n
,那么后面就是HTTP Body。浏览器读取HTTP Body,并根据Header信息中指示的Content-Type
、Content-Encoding
等解压后显示网页、图像或其他内容。
通常浏览器获取的第一个资源是HTML网页,在网页中,如果嵌入了JavaScript、CSS、图片、视频等其他资源,浏览器会根据资源的URL再次向服务器请求对应的资源。
使用TCP多线程编程服务器框架
package com.wang.web; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; public class Server { public static void main(String[] args) throws IOException { //监听指定接口 ServerSocket ss = new ServerSocket(8080); System.out.println("server is running..."); for (; ; ) { Socket socket = ss.accept(); System.out.println("connnection from" + socket.getRemoteSocketAddress()); Thread thread = new Handler(socket); thread.start(); } } } class Handler extends Thread{ Socket socket; public Handler(Socket socket){ this.socket = socket; } public void run(){ try(InputStream inputStream = this.socket.getInputStream()){ try(OutputStream outputStream = this.socket.getOutputStream()){ handle(inputStream,outputStream); } }catch (Exception e){ try{ this.socket.close(); }catch (IOException ioe){ } System.out.println("client disconnected"); } } private void handle(InputStream inputStream,OutputStream outputStream)throws IOException{ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream,StandardCharsets.UTF_8)); //处理HTTP请求 } }
HTTP目前有多个版本,1.0
是早期版本,浏览器每次建立TCP连接后,只发送一个HTTP请求并接收一个HTTP响应,然后就关闭TCP连接。由于创建TCP连接本身就需要消耗一定的时间,因此,HTTP 1.1允许浏览器和服务器在同一个TCP连接上反复发送、接收多个HTTP请求和响应,这样就大大提高了传输效率。
我们注意到HTTP协议是一个请求-响应协议,它总是发送一个请求,然后接收一个响应。能不能一次性发送多个请求,然后再接收多个响应呢?HTTP 2.0可以支持浏览器同时发出多个请求,但每个请求需要唯一标识,服务器可以不按请求的顺序返回多个响应,由浏览器自己把收到的响应和请求对应起来。可见,HTTP 2.0进一步提高了传输效率,因为浏览器发出一个请求后,不必等待响应,就可以继续发下一个请求。
HTTP 3.0为了进一步提高速度,将抛弃TCP协议,改为使用无需创建连接的UDP协议,目前HTTP 3.0仍然处于实验阶段。
2. Tomcat服务器
开启服务器后才可以访问webapp中的项目
3. Servlet
开发动态web的一门技术
-
编写一个类实现Servlet接口
-
把开发好的Java类部署到web服务器中
把实现了Servlet接口的java程序叫做Servlet
用户携带的参数不同,显示的界面也不同
3.1 HelloServlet
-
继承HttpServlet类
-
实现Post和Get方法(其他方法暂时不用)
编写实现类
import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); writer.print("Hello,Servlet"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
-
编写Servlet的映射
-
Java程序要通过浏览器访问,而浏览器需要访问服务器
-
所以,要在web服务中注册我们所写的Servlet,还要交
-
给他一个浏览器能够访问的路径
-
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd" version="5.0"> <!--注册Servlet--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.wang.ServletTest.TestServlet</servlet-class> </servlet> <!--servlet映射的地址--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
-
配置Tomcat
配置项目路径
-
启动测试
3.2 执行流程
Servlet对象由tomcat服务器创建,并且service方法由tomcat调用
3.3 生命周期
-
加载和实例化
-
初始化
-
一个Servlet只会创建一次
-
package com.wang.servletTest; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException; @WebServlet(urlPatterns = "/demo2",loadOnStartup = 1) public class ServletDemo2 implements Servlet { //初始化方法 //调用时机:默认情况下Servlet被第一次访问时调用 //调用次数:1 @Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("Init...................."); } //开始服务 //调用时机:每一次servlet被访问时 //调用次数:n @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("service-..........................."); } //结束服务-销毁 //调用时机:服务器关闭或内存释放 //调用次数:1 @Override public void destroy() { System.out.println("destory......................."); } @Override public ServletConfig getServletConfig() { return null; } @Override public String getServletInfo() { return null; } }
3.4 Servlet方法
package com.wang.servletTest; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(urlPatterns = "/demo3") public class ServletDemo3 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........."); } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/tomcat_demo2_war/demo3" method="post"> <input name="username"><input type="submit"> </form> 点击提交之后,就会调用demo3中的Servlet,且是dopost的方法 </body> </html>
针对不同的提交方式,Servlet中的service方法都需要编写一下代码
//根据请求方式的不同get/post 需要进行不同的解析服务方式 @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { //根据方式不同,进行分别处理 //1.获取请求方式-------servletRequest对象可以提供请求方式 HttpServletRequest request = (HttpServletRequest) servletRequest; String method = request.getMethod(); //2.根据不同的请求方式编写不同的逻辑代码 if ("GET".equals(method)){ //get的处理逻辑 }else if("POST".equals(method)){ //post的处理逻辑 } }
3.5 urlPattern
-
Servlet要想被访问,必须配置其访问路径(urlPattern)
-
一个Servlet,可以配置多个urlPattern
-
@WebServlet(urlPatterns = {"/demo1","/demo2"})
-
-
urlPattern配置规则
-
精确匹配
-
目录匹配
-
扩展名匹配
-
任意匹配
-
-
-
当一个路径满足多种匹配规则时,越精确的被调用
-
DefaultServlet是Tomcat用于处理静态资源的servlet,如果被覆盖掉那么将无法调用静态资源(比如 html)
3.6 XML编写
不使用注解,使用XML配置的方式
<!--Servlet全类名--> <servlet> <servlet-name>demo4</servlet-name> <servlet-class>com.wang.servletTest.ServletDemo4</servlet-class> </servlet> <!--Servlet路径映射--> <servlet-mapping> <servlet-name>demo4</servlet-name> <url-pattern>/demo4</url-pattern> </servlet-mapping>
4. Request 和 Response
-
Request 获取请求数据
-
Response 设置响应的数据
package com.wang.servletTest; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/demo5") public class ServletDemo5 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //使用request对象获得请求数据 String name = req.getParameter("name"); //使用response对象设置响应数据 resp.setHeader("content-type","text/html;charset=utf-8"); resp.getWriter().write("h1"+name+"欢迎!</h1>"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //使用request对象获得请求数据 String name = req.getParameter("name"); //使用response对象设置响应数据 resp.setHeader("content-type","text/html;charset=utf-8"); resp.getWriter().write("<h1>"+name+"欢迎!</h1>"); } }
4.1 Request对象
4.1.1继承体系
-
ServletRequest 是一个接口
-
HttpServletRequest 是对Http协议封装的request接口
-
Tomcat提供了实现类(Tomcat需要解析这些数据,所以需要提供实现类)
4.1.2 获取请求数据
请求数据分为三部分:
-
请求行
-
请求头
-
请求体
同一种方式获取不同请求的参数:
Request对象采取的方式:
-
建立一个Map
-
泛型为<String,String[]>
-
编写三个通用的调用参数的方法
4.1.3 请求转发
-
一种在服务器内部的资源跳转方式(forward)
4.2 Response对象
响应数据分为三部分:
-
响应行
-
响应头
-
响应体
4.2.1重定向
-
一种资源跳转方式
-
重定向是浏览器接收到302后自动的请求新地址的行为
-
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("resp1..................."); /*重定向 //1.设置响应状态码 resp.setStatus(302); //2.设置响应头 resp.setHeader("Location","/tomcat_demo2/resp2");*/ //简化方法 resp.sendRedirect("/tomcat_demo2/resp2"); }
-
重定向与请求转发的区别
4.2.2 响应体数据设置
响应字符数据:
-
通过Response对象获取字符输出流
PrintWriter writer = reps.getWriter();
-
写数据
writer.write("aaa")
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置支持utf-8 resp.setContentType("text/html;charset=utf-8"); //扫描并写入数据 PrintWriter writer = resp.getWriter(); writer.write("呵呵呵哒好玩的"); }
该流不需要关闭,response对象会被服务器销毁
响应字节数据(除字符外的文件类型):
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.读取文件 FileInputStream stream = new FileInputStream("f://Anson Seabra - Keep You Head Up Princess.mp3"); //2.获取字节输出流 ServletOutputStream os = resp.getOutputStream(); /*3.完成流的复制 笨办法 byte[] buff = new byte[1024]; int len = 0; while ((len=stream.read(buff))!=-1){ os.write(buff,0,len); }*/ IOUtils.copy(stream,os); stream.close(); }
5. 登录案例
5.1 用户注册
-
用户注册,发送给RegisterServlet
-
在RegisterServlet中使用MyBatis保存数据
-
保存前需要查重(查询用户名)
package com.itheima.web; import com.itheima.mapper.UserMapper; import com.itheima.pojo.User; import com.itheima.util.SqlSessionFactoryUtils; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.io.InputStream; @WebServlet("/registerServlet") public class RegisterServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1. 接收用户数据 String username = request.getParameter("username"); String password = request.getParameter("password"); //封装用户对象 User user = new User(); user.setUsername(username); user.setPassword(password); //2. 调用mapper 根据用户名查询用户对象 //2.1 获取SqlSessionFactory对象 /* String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);*/ SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); //2.2 获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //2.3 获取Mapper UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //2.4 调用方法 User u = userMapper.selectByUsername(username); //3. 判断用户对象释放为null if( u == null){ // 用户名不存在,添加用户 userMapper.add(user); // 提交事务 sqlSession.commit(); // 释放资源 sqlSession.close(); }else { // 用户名存在,给出提示信息 response.setContentType("text/html;charset=utf-8"); response.getWriter().write("用户名已存在"); } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
5.2 用户登录
-
用户登录,填写账号密码提交到LoginServlet
-
在LoginServlet使用MyBatis查询数据库,匹配账号和密码
-
错误则响应登录失败
package com.itheima.web; import com.itheima.mapper.UserMapper; import com.itheima.pojo.User; import com.itheima.util.SqlSessionFactoryUtils; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; @WebServlet("/loginServlet") public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1. 接收用户名和密码 String username = request.getParameter("username"); String password = request.getParameter("password"); //2. 调用MyBatis完成查询 //2.1 获取SqlSessionFactory对象 /* String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);*/ SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); //2.2 获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //2.3 获取Mapper UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //2.4 调用方法 User user = userMapper.select(username, password); //2.5 释放资源 sqlSession.close(); //获取字符输出流,并设置content type response.setContentType("text/html;charset=utf-8"); PrintWriter writer = response.getWriter(); //3. 判断user释放为null if(user != null){ // 登陆成功 writer.write("登陆成功"); }else { // 登陆失败 writer.write("登陆失败"); } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
6. JSP
html和java语句可以放到同一个文档里,简化开发
Jsp脚本用于编写java代码
-
<%....%>
-
内容会直接放到jspService中去
-
-
<%=....%>
-
内容会放到out.print中去,作为out.print的参数
-
-
<%!....%>
-
内容会放到JSPService方法之外,被类直接包含(成员地位)
-
6.1 EL表达式
用于获取数据
${expression}
7. MVC和三层架构
8. 会话跟踪技术
-
会话是与浏览器绑定
-
会话跟踪是服务器识别多次请求是否来自同一浏览器发出的
8.1 Cookie
-
服务器setCookie 通过HTTP发送给浏览器
-
浏览器下次请求时就会携带上上次服务器发来的Cookie(可能会有很多Cookie)
-
按照键去查找需要的Cookie
-
8.2 Session
-
将会话数据保存到服务端
-
Session是基于Cookie的
8.3 对比
例如:验证码的实现就不能是Cookie,因为Cookie是保存在浏览器中的