Javaweb
1.1 前言
-
静态web
-
HTML、css
-
提供给所有人看的数据始终不会发生变化
-
-
动态web
-
几乎所有的网站都是
-
提供给所有人看的数据始终会发生变化
-
技术栈:servlet/jsp、ASP、PHP
-
在Java中,动态web资源开发的技术统称为Javaweb
1.2 web应用程序
-
web应用程序:可以提供浏览器访问的程序
-
能访问的所有页面资源,都存在于这个世界的某一个角落的计算机上
-
一个web应用由多部分组成(静态web、动态web):
-
html、css、js
-
jsp、servlet
-
Java程序
-
jar包
-
配置文件
-
..............
-
-
web应用程序编写完毕后,若想提供给外界访问,需要一个服务器来统一管理
1.3 静态web
*.htm、 *.html这些都是网页的后缀,如果服务器上一直存在这些东西,我们就可以直接进行读取
静态web存在的缺点:
-
web页面无法动态更新,所有用户看到的都是同一个页面
-
无法和数据库进行交互(数据无法持久化,用户无法交互)
1.4 动态web
页面会动态展示:“web的页面展示效果因人而异”
缺点:加入服务器的动态资源出现了错误,需要重新编写后台程序,重新发布
优点:
-
web页面可以动态更新,所有用户看到的都是不同的页面
-
可以和数据库进行交互(数据持久化)
2. web服务器
2.1 技术讲解
ASP:
-
微软出品,国内最早流行的
-
在html中嵌入了vb的脚本 ASP+COM
-
在ASP开发中,基本一个页面就有几千行的代码,页面极其混乱,所以维护成本很高
PHP:
-
PHP开发速度很快,功能很强大,跨平台,代码很简单
-
但是无法承载大访问量的情况(局限性)
JSP/Servlet:
-
sun公司主推的B/S架构 (B/S:浏览器和服务器 C/S:客户端和服务器)
-
基于Java语言的(所有的大公司,或者一些开源的组件,都是用Java写的)
-
可以承载三高(高并发、高可用、高性能)带来的影响
2.2 web服务器
web服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息
IIS:微软的:ASP.......Windows中自带的
Tomcat:
Tomcat是Apache 软件基金会的Jakarta 项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,它是最佳选择
Tomcat 实际上运行JSP 页面和Servlet
高难度面试题:请你谈谈网站是如何进行访问的
当输入域名,回车后:
-
首先,检查本地的C:\WINDOWS\System32\drivers\etc\host 配置文件下有没有这个域名映射
-
如果有:直接访问了
-
如果没有:联网的状态去DNS服务器找,找到的话就返回,找不到就返回找不到
3. HTTP
3.1 什么是HTTP
HTTP(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上。
-
HTTP端口号:80
-
文本:html、字符串......
-
超文本:图片、视频、音乐、定位、地图......
HTTPS: S: Secure 安全的,保护的
-
HTTPS端口号:443
3.2 两个时代
HTTP1.0:
客户端和web服务器连接后,只能获得一个web资源
HTTP1.1:
客户端和web服务器连接后,可以获得多个web资源
3.3 HTTP请求
-
客户端---发请求(Request)---服务器
以百度为例:
请求行:
//请求地址
Request URL: https://www.baidu.com/
//请求方式:get/post方法
//get:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全。但高效
//post:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,安全。但不高效
Request Method: GET
//状态码:200标识成功
Status Code: 200 OK
//remote:远程 远程地址
Remote Address: 220.181.38.150:443
消息头:
//告诉浏览器,它所支持的数据类型
Accept: text/html
//支持那种编码格式:GBK、UTF-8、GB2312
Accept-Encoding: gzip, deflate, br
//告诉浏览器它的语言环境
Accept-Language: zh-CN,zh;q=0.9
//告诉浏览器,请求完成时断开还是保持连接
Connection: keep-alive
3.4 HTTP响应
-
服务器---响应---客户端
以百度为例:
//缓存控制
Cache-Control: private
//连接
Connection: keep-alive
//编码
Content-Encoding: gzip
//类型
Content-Type: text/html
响应体:
Accept: 告诉浏览器,它所支持的类型
Accept-Encoding: 支持哪种编码格式
Accept-Language: 告诉浏览器,它的语言环境
Cache-Controller:缓存控制
Connection: 告诉浏览器,请求完成是断开还是保持连接
Host: 主机...
Refresh:告诉客户端,多久刷新一次
location:让网页重新定位
响应状态码:
200:请求响应成功
3xx:请求重定向 (重定向:重新到给的新位置)
4xx:找不到资源(404)
5xx:服务器代码错误 (500) 502:网关错误
常见面试题:当你的浏览器中地址栏输入地址并回车的一瞬间到网页能都展示回来,经历了什么?
1.(域名解析):在客户端,浏览器输入地址后,首先会在windows系统文件的hosts中查找是否有对应的ip地址,如果有,直接访问了,如果没有则需要向DNS域名解析服务器询问该域名对应的ip地址。
2.(TCP三次握手)获取相应的ip地址后,客户端与服务器端在对应端口上建立TCP连接(三次握手),(网络层,数据链路层,物理层)
三次握手-->
第一次握手:客户端向服务器端发送一个SYN段,该段中包含客户端的初始序列号。
第二次握手:服务器端返回客户端SYN+ACK,该端中包含服务器端的初始序列号,ACK表示,已经确定收到客户端的SYN段。
第三次握手:客户端向服务器端响应一个ACK端,ACK表示,已经确定接受到服务器端的SYN段。
3.(建立起TCP连接后发起http请求)客户端向服务器端发送请求,包含请求行,请求头。主要的两种请求方式(GET与POST)
-->GET:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据的内容,不安全,但高效。
-->POST:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效。
4.(服务器响应http请求)服务器处理请求,并返回响应,包含状态码,响应头,响应体。
5.(浏览器解析http代码)浏览器收到响应,解析http代码渲染页面,并在浏览器页面展示出来。
6.(断开连接)http1.0短连接,http1.1长连接。
4. Servlet
4.1 Servlet简介
Servlet(Server Applet)是JavaServlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
Servlet是指任何实现了这个Servlet接口的类,Servlet运行于支持Java的应用服务器中。
如果想开发一个Servlet程序,只需要完成两个小步骤:
-
编写一个类,实现Servlet接口
-
把开发好的Java类部署到web服务器中
把实现了Servlet接口的Java程序叫做:Servlet
4.2 HelloServlet
Servlet接口在sun公司有两个默认的实现类:GenericServlet,HttpServlet(GenericServlet实现了Servlet,HttpServlet实现了GenericServlet)
-
构建一个普通的Maven项目,删掉里面的src目录,以后我们的学习就可以在这个项目里面建立Moudel;
这个空的工程就是Maven主工程
关于Maven父子工程的理解:
父项目中会有:
<modules>
<module>servlet_01</module>
</modules>子项目中会有:
<parent>
<artifactId>javaweb_02_servlet</artifactId>
<groupId>com.zcc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>父项目中的jar包子项目可以直接使用
相当于继承关系
-
然后在子项目中完成一系列的配置,包括添加java、resources包;添加Tomcat,运行,出现HelloWorld!界面就OK了
-
编写一个Servlet程序
-
编写一个普通类
-
实现Servlet接口,这里我们直接继承HttpServlet
package com.zcc.servlet;
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 MyFirstServlet extends HttpServlet {
//由于get和post只是请求的不同的方式,可以相互调用,业务逻辑都一样
-
-
编写Servlet的映射
为什么需要映射?
我们的写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的Servlet,还需要给它一个浏览器能够访问的路径
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>MyFirstServlet</servlet-name> <servlet-class>com.zcc.servlet.MyFirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyFirstServlet</servlet-name> <url-pattern>/MyFirstServlet</url-pattern> </servlet-mapping> </web-app>
-
项目运行
4.3 Servlet原理
Servlet是由Web服务器调用,web服务器在收到浏览器请求之后, 会判断servlet是否存在,若不存在则装载创建servlet的实例并初始化(若存在则跳过此步骤),然后调用service方法对请求进行处理。
步骤:
-
Web Client 向Servlet容器(Tomcat)发出Http请求
-
Servlet容器接收Web Client的请求
-
Servlet容器创建一个HttpRequest对象,将Web Client请求的信息封装到这个对象中。
-
Servlet容器创建一个HttpResponse对象
-
Servlet容器调用HttpServlet对象的doservice方法,把HttpRequest对象与HttpResponse对象作为参数传给HttpServlet 对象。
-
HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息。
-
HttpServlet调用HttpResponse对象的有关方法,生成响应数据。
-
Servlet容器把HttpServlet的响应结果传给Web Client。
4.4 ServletContext
web容器在启动的时候,它会为每个web程序创建一个对应的ServletContext对象,这个ServletContext对象就代表了当前的web应用。
它有一下作用:
1. 共享数据
就是我在这个Servlet中保存的数据,可以在另外一个servlet中拿到。(通过ServletContext获取,因为保存的数据都放在了ServletContext中)
FirstServlet:
//存数据 public class FirstServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); //Servlet上下文 String username="张三"; //数据 servletContext.setAttribute("name",username); //将一个数据存放到了ServletContext中,起名字为name,值为username(张三) }
SecondServlet
//获取FirstServlet存的数据 public class SecondServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); String name = (String) servletContext.getAttribute("name"); resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); PrintWriter writer = resp.getWriter(); writer.print("用户名:"+name); writer.close(); }
配置web.xml
<servlet> <servlet-name>FirstServlet</servlet-name> <servlet-class>com.zcc.servlet.FirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FirstServlet</servlet-name> <url-pattern>/FirstServlet</url-pattern> </servlet-mapping> <servlet> <servlet-name>SecondServlet</servlet-name> <servlet-class>com.zcc.servlet.SecondServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>SecondServlet</servlet-name> <url-pattern>/SecondServlet</url-pattern> </servlet-mapping>
启动测试:
2. 获取初始化参数
在web.xml文件配置初始化参数
<context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost/3306/mybatis</param-value> </context-param>
编写Servlet
//获取初始化参数 public class ServletDemo03 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); String url = servletContext.getInitParameter("url"); PrintWriter writer = resp.getWriter(); writer.print(url); writer.close(); } }
在web.xml配置文件配置对应的Servlet
<servlet> <servlet-name>ServletDemo03</servlet-name> <servlet-class>com.zcc.servlet.ServletDemo03</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletDemo03</servlet-name> <url-pattern>/ServletDemo03</url-pattern> </servlet-mapping>
启动测试:
3. 请求转发
编写Servlet
//请求转发 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/ServletDemo03"); //获得转发的请求路径 requestDispatcher.forward(request,response); //调用forward实现请求转发 }
在web.xml配置文件配置对应的Servlet
<servlet> <servlet-name>ServletDemo04</servlet-name> <servlet-class>com.zcc.servlet.ServletDemo04</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletDemo04</servlet-name> <url-pattern>/ServletDemo04</url-pattern> </servlet-mapping>
启动测试:
4. 读取资源文件
properties:在resources目录下新建一个db.properties
思路:需要一个文件流
username=root password=root
编写Servlet,读取db.properties
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); InputStream resourceAsStream = servletContext.getResourceAsStream("/WEB-INF/classes/db.properties"); Properties properties = new Properties(); properties.load(resourceAsStream); String username = properties.getProperty("username"); String password = properties.getProperty("password"); PrintWriter writer = resp.getWriter(); writer.print(username+":"+password); }
在web.xml配置文件配置对应的Servlet
<servlet> <servlet-name>ServletProperties</servlet-name> <servlet-class>com.zcc.servlet.ServletProperties</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletProperties</servlet-name> <url-pattern>/ServletProperties</url-pattern> </servlet-mapping>
启动测试:
5. HttpServletResponse
下载文件
步骤:
-
获取下载文件的路径
-
获取下载的文件名
-
设置想办法让浏览器能够支持下载我们需要的东西
-
获取下载文件的输入流
-
创建缓冲区
-
获取OutputStream对象
-
将FileOutputStream流写入缓冲区
-
使用OutputStream将缓冲区中的数据输出到客户端
编写Servlet
public class FileServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1. 获取下载文件的路径 String realPath="D:\\JavaWeb\\源代码\\javaweb_02_servlet\\servlet_response\\src\\main\\resources\\image\\fd.jpg"; //2. 获取下载的文件名 String filename = realPath.substring(realPath.lastIndexOf("\\")+1); //3. 设置想办法让浏览器能够支持下载我们需要的东西:Web下载文件设置头信息 resp.setHeader("Content-disposition","attachment;filename=" + URLEncoder.encode(filename,"utf-8")); //4. 获取下载文件的输入流 FileInputStream fileInputStream = new FileInputStream(realPath); //5. 创建缓冲区 int len=0; byte[] buffer = new byte[1024]; //6. 获取OutputStream对象 ServletOutputStream outputStream = resp.getOutputStream(); //7. 将FileOutputStream流写入缓冲区 使用OutputStream将缓冲区中的数据输出到客户端 while ((len=fileInputStream.read(buffer))>0){ outputStream.write(buffer,0,len); } //8. 关闭资源 outputStream.close(); fileInputStream.close(); }
在web.xml配置文件配置对应的Servlet
启动测试:
验证码实现
编写Servlet
//实现在网页3秒刷新一个验证码 public class ImageServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //让浏览器3秒自动刷新一次 resp.setHeader("refresh","3"); //在内存中创建一个图片 BufferedImage image = new BufferedImage(80, 30, BufferedImage.TYPE_INT_RGB); //得到图片 Graphics2D g = (Graphics2D) image.getGraphics(); //画笔 //设置图片的背景颜色 g.setColor(Color.red); g.fillRect(0,0,80,20); //给图片写数据 g.setColor(Color.BLUE); g.setFont(new Font(null,Font.BOLD,20)); g.drawString(RandomNumber(),0,15); //告诉浏览器,这个请求要用图片的方式打开 resp.setContentType("image/png"); //存在缓存,不能让浏览器缓存 resp.setDateHeader("Expires", 0); resp.setHeader("Cache-Control", "no-cache"); resp.setHeader("Pragma", "no-cache"); //把图片写给浏览器 ImageIO.write(image,"png",resp.getOutputStream()); } //生成随机数 private String RandomNumber(){ Random random = new Random(); String num=random.nextInt(999999)+""; return num; } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
在web.xml配置文件配置对应的Servlet
启动测试:
实现重定向(最重要)
请求转发:
重定向:
重定向常见场景:用户登录跳转、........
实现重定向:
编写Servlet: 就一行代码
//重定向 public class RedirectServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.sendRedirect("/servlet_response_war/HelloServlet"); }
在web.xml配置文件配置对应的Servlet
启动测试:
面试题:聊聊重定向和转发的区别
语法:
-
请求转发:request.getRequestDispatcher(URL地址).forward(request, response)
-
重定向: response.sendRedirect(URL地址)
相同点:
-
页面都会发生跳转
不同点:
-
请求转发的时候,url不会产生变化 307
-
重定向的时候,url会发生变化 302
-
请求转发是一次请求,重定向是二次请求
请求转发是内部跳转,仅返回结果,所以地址是不会变的。但是重定向是先返回地址,再重新访问,所以地址会变
6. HttpServletRequest
获取前端传来的参数,请求转发
先编写index.jsp页面
<html> <body> <%-- 这里提交的路径需要寻找项目的路径 ${pageContext.request.contextPath} 项目根路径 --%> <form action="${pageContext.request.contextPath}/RequestTest" method="post"> 用户名:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> 爱好: <input type="checkbox" name="hobbys" value="女孩">女孩 <input type="checkbox" name="hobbys" value="code">代码 <input type="checkbox" name="hobbys" value="eat">吃 <input type="checkbox" name="hobbys" value="play">玩 <br> <input type="submit"> </form> </body> </html>
编写Servlet
//获取前端传来的参数,请求转发 public class RequestTest extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置编码问题 ,请求的参数设置为utf-8 响应的也是utf-8 req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); //处理请求 String username = req.getParameter("username"); //getParameter():取参数的方法。把jsp文件中的数据读取出来 String password = req.getParameter("password"); String[] hobbys = req.getParameterValues("hobbys"); //获取多个参数 System.out.println(username+":"+password); System.out.println(Arrays.toString(hobbys)); //用request请求转发 req.getRequestDispatcher("/success.jsp").forward(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
编写转发到的jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>success</h1> </body> </html>
在web.xml配置文件配置对应的Servlet
启动测试:
5. cookie与session
5.1 什么是会话
会话:用户打开一个浏览器,点击了很多链接,访问多个web资源,然后关闭浏览器,这个过程可以称之为会话。
会话跟踪是web程序中常用的技术,用来跟踪用户的整个会话,常用的会话跟踪技术是Cookie与Session 。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份
5.2 cookie
-
从请求中拿cookie信息
-
服务器响应给客户端cookie信息
cookie的常用方法:
Cookie[] cookies = req.getCookies(); //获取所有cookie信息 cookie.getName() //获取cookie的名称 cookie.getValue(); //获取cookie的值 //创建cookie Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + ""); cookie.setMaxAge(24 * 60 * 60); //设置cookie的有效期
-
一个cookie只能保存一个信息
-
一个web站点可以给浏览器发送多个cookie,最多存放20个cookie
-
cookie大小有限制:4kb
-
浏览器存放cookie的上限:300个
删除cookie的方法:
-
不设置有效期,关闭浏览器,自动失效
-
设置有效期时间为0
编码解码(几乎可以解决所有的乱码问题)
//编码 URLEncoder.encode("张三","utf-8") //解码 URLDecoder.decode(cookie.getValue(),"UTF-8")
5.3 session(重点)
什么是session?
-
服务器会给每一个用户(浏览器)创建一个session对象;
-
一个session独占一个浏览器,只要浏览器没有关闭,这个session就存在
-
session保存后,只要用户登陆,整个网站它都可以直接访问-->用途:保存用户的登录信息;保存购物车信息......
session中的方法:
session和cookie的区别:
-
cookie是把用户的数据写给用户的浏览器。浏览器保存(可以保存多个)
-
session是把用户的数据写到用户独占session中,服务端保存(保存重要的信息,减少服务器资源的浪费)
-
session对象由服务器创建
session的使用:
//测试session01 public class Test01 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //编码问题 req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); //得到session HttpSession session = req.getSession(); //给session中存东西 session.setAttribute("name","张三"); session.setAttribute("password","123456"); session.setAttribute("zhangsan",new Person(1,"张三","123456")); session.setAttribute("pangya",new Person(2,"胖丫","666666")); //获得session的id和创建时间 String id = session.getId(); long creationTime = session.getCreationTime(); //判断session是不是新创建的 if (session.isNew()) { PrintWriter writer = resp.getWriter(); writer.println("session创建成功"); writer.println("sessionId:"+id); writer.println("session创建时间:"+new Date(creationTime)+""); writer.close(); }else { PrintWriter writer = resp.getWriter(); writer.println("session已经存在了"); writer.println("sessionId:"+id); writer.println("session创建时间:"+new Date(creationTime)+""); writer.close(); } //运行后发现,请求带了一个cookie,猜测sessionid是由cookie传进去的 // session创建的时候做了什么事 // Cookie cookie = new Cookie("JSESSIONID", id); // resp.addCookie(cookie); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
取出session数据:
//取出session存的东西 public class Test02 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //编码问题 req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); //得到session HttpSession session = req.getSession(); //取数据 String name = (String) session.getAttribute("name"); String password = (String) session.getAttribute("password"); Person zhangsan = (Person) session.getAttribute("zhangsan"); Person pangya = (Person) session.getAttribute("pangya"); System.out.println(name); System.out.println(password); System.out.println(zhangsan); System.out.println(pangya); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
手动注销session
//手动注销session public class Test03 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //编码问题 req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); //得到session HttpSession session = req.getSession(); //手动注销session session.invalidate(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
web.xml中设置时间可自动注销session
<!--自动注销session :设置15分钟后注销(session只保留15分钟) 单位是分钟--> <session-config> <session-timeout>1</session-timeout> </session-config>
6. jsp
6.1 什么是jsp
jsp:Java Server Pages Java服务端页面,也和Servlet一样,用于动态Web技术
最大的特点:
-
写JSP就像在写HTML
-
JSP和HTML区别:
-
HTML只给用户提供静态的数据
-
JSP页面中可以嵌入JAVA代码,为用户提供动态数据
-
6.2 jsp原理
思路:JSP到底是怎么执行的
-
代码层面没有问题
-
是服务器内部工作
-
tomcat中由一个work目录;
-
IDEA中使用Tomcat的话会在IDEA的tomcat中生成一个work目录
-
可以发现,jsp页面转变为了java程序
因为:浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet
所以:JSP最终也会被转换成一个java类
JSP本质上就是一个Servlet
jsp被编译后的样子 :
底层编译后就像servlet的流那样的输出方式.
得到一个请求时,首先会判断请求
看看这些部分内置对象:
final javax.servlet.jsp.PageContext pageContext;//pageContext 页面上下文 javax.servlet.http.HttpSession session = null;//session final javax.servlet.ServletContext application;//servletContext final javax.servlet.ServletConfig config;//config 配置 javax.servlet.jsp.JspWriter out = null; //out; 输出 final java.lang.Object page = this; //page; 当前页面 还有request 请求, reponse 响应
输出页面时之前的代码;自动添加的.
response.setContentType("text/html;charset=UTF-8");//设置响应页面类型 pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out;
过程:
在jsp页面中
只要是java代码就会原封不动的输出
如果是HTML代码,就会被转换为:
out.write("<html>\r\n"); 这样的格式输出到前端
6.3 jsp的基本语法与指令
基本语法
用于将程序输出-->客户端
<%=new Date()%> 语法:<%=变量或者表达式%> 用EL表达式可直接写为 ${ 变量或表达式 };这样对于那些不存在的数,就不会输出为null
jsp脚本片段
<% int num=0; for (int i = 0; i < 5; i++) { num+=i; } out.print("<h1>"+num+"</h1>"); %>
可以在代码中放入HTML元素
<% for (int i = 0; i < 10; i++) { %> <p>这是一个段落</p> <% } %>
jsp声明(全局变量、代码块、方法)
<%! static { System.out.println("我是静态代码块"); } private int axc=100; public void test(){ System.out.println("我是方法"); } %>
注意:声明被编译后。位置和之前定义的不一样
jsp的注释,不会被编译、安全性高
<%--注释--%>
指令
page指令设置字符编码,语言类型,不忽略EL表达式
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
page指令中导包
<%@ page import="java.util.Date" %>
page指令中跳转错误页面(可以定制错误页面)
<%@ page errorPage="error/500.jsp" %>
当然。错误跳转也可以在web.xml中配置
<!--配置错误页面--> <error-page> <error-code>404</error-code> <location>/error/404.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/error/500.jsp</location> </error-page>
page指令中也可以显示地 标出错误页面
<%@ page isErrorPage="true" %>
在include指令中,提取公共页面的信息
静态包含指的是在编译期间,把包含的页面也编译到当前页面的java文件中,也就是编译时就将两个jsp文件合二为一
<%@ include file="/common/header.jsp"%>
动态包含:在jsp页面中动态包含另一个资源,在运行期间,访问被包含的页面,并将响应结果通包含页面的响应结果合并,生成最终响应
<jsp:include page=“被包含页面()” flush=“true或者false”/>
6.4 内置对象与作用域
JSP的内置对象是指在JSP页面系统中已经默认内置的Java对象,这些对象不需要开发人员显式声明即可使用。
9大内置对象: out 向客户端输出
pageContext 用于访问page的各种对象 (可存数据)
request 封装用户请求 (可存数据) response 向用户做出响应 session 客户和服务器间的会话 (可存数据)
application 于服务器启动时开始运行,用来存放全局变量,可在用户间共享 (可存数据) exception 异常 config 初始化要用的参数 page JSP页面本身
就存数据而言:作用域关系:
pageContext.setAttribute("id1",1); //保存的数据只在一个页面中有效 request.setAttribute("id2",2); //保存的数据只在一次请求中有效,请求转发会携带数据 session.setAttribute("id3",3); //保存的数据只在一次会话中有效,即打开浏览器到关闭浏览器 application.setAttribute("id4",4); //保存的数据在服务器中有效,即打开服务器到关闭服务器
在页面请求转发:
-
直接使用pageContext对象调用forward()方法
<% pageContext.forward("/qu.jsp"); %>
-
使用request的方式
<% request.getRequestDispatcher("/qu.jsp").forward(request,response); %>
练习:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%--存数据--%> <% pageContext.setAttribute("pageContext",1); //保存的数据只在一个页面中有效 request.setAttribute("request",2); //保存的数据只在一次请求中有效,请求转发会携带数据 session.setAttribute("session",3); //保存的数据只在一次会话中有效,即打开浏览器到关闭浏览器 application.setAttribute("application",4); //保存的数据在服务器中有效,即打开服务器到关闭服务器 %> <%--获取数据 可以都使用pageContext.findAttribute方法 若没有指定的获取的是哪个域对象,则先后顺序为 pageScope、requestScope、sessionScope和applicationScope。尤其是几个域对象有同名属性时. --%> <% Integer pageContext1 = (Integer) pageContext.findAttribute("pageContext"); Integer request1 = (Integer) pageContext.findAttribute("request"); Integer session1 = (Integer) pageContext.findAttribute("session"); Integer application1 = (Integer) pageContext.findAttribute("application"); %> <%--在页面展示数据 用EL表达式,不会出现null值 --%> <% out.println(pageContext1); out.println(request1); out.println(session1); out.println(application1); %> </body> </html>
在另一个请求中获取
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <% Integer pageContext1 = (Integer) pageContext.findAttribute("pageContext"); Integer request1 = (Integer) pageContext.findAttribute("request"); Integer session1 = (Integer) pageContext.findAttribute("session"); Integer application1 = (Integer) pageContext.findAttribute("application"); %> <%--在页面展示数据 --%> <% out.println(pageContext1); out.println(request1); out.println(session1); out.println(application1); %> </body> </html>
6.5 EL表达式、JSP标签、JSTL标签
EL表达式,作用:
-
获取数据
-
执行运算
-
获取web开发的常用对象
JSP标签
-
动态包含:上边有
<jsp:include page=“被包含页面()” flush=“true或者false”/>
-
转发页面,可携带数据信息
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%--(2)请求转发,可携带数据--%> <jsp:forward page="/demoforward.jsp"> <jsp:param name="name" value="tom"/> <jsp:param name="age" value="21"/> </jsp:forward> </body> </html>
JSTL标签
什么是JSTL?
JSP标准标识库,使用JSTL可实现JSP页面的逻辑处理; 可用于编写各种动态JSP页面 。 它主要提供给Java Web开发人员一个标准通用的标签库
导入依赖:
<!--jstl表达式的依赖--> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl-api</artifactId> <version>1.2</version> </dependency> <!--standard标签库--> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency>
添加标签库
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
这里的uri 标识符
指向jar包的tld
文件,prefix
为前缀,可以自定义,一般定义为c
;也称为c标签
使用JSTL标签
刚才用c作为前缀的,那么直接写<c:标签 , 标签属性>内容</c:标签 > 即可
条件标签 —if 具体使用查资料
if标签的几个属性 在test中可写入条件判断(仅有test支持使用el标签); var定义属性名(用于保存test中的判断结果),scope声明作用范围(默认为page,即PageContext域对象); 将该标签的test返回结果自动赋值给var,再由scope决定哪个域对象可以调用;
迭代标签 —forEach 具体使用查资料
forEach对Java中的集合与数组进行遍历
forEach标签的几个属性:
(1)items : 获取需要迭代的集合或数组,支持EL表达式;类型为数组,字符串,集合;
(2)var : 定义一个变量,接收循环中获取的数据;不支持EL表达式,类型为String;
(3)varStatus : 获取循环的状态信息,不支持 EL表达式,类型为String; varStatus调用的几个参数:常用index,count
7. JavaBean
就是实体类
必须要有一个无参构造,且属性全部是私有的;属性要有对应的get、set方法
ORM:对象关系映射
-
表对应类
-
字段对应属性
-
行记录对应对象
8. MVC三层架构
M:model 模型
V: view 视图
C: controller 控制器
流程:
Model
-
业务处理:业务逻辑(Service)
-
数据持久层:CRUD(增删改查) (Dao)
View
-
展示数据
-
提供链接发起Servlet请求
Controller
-
接收用户的请求(req:请求参数 、Session信息.....)
-
交给业务层处理对应的代码
-
控制视图的跳转
以登录为例:
登录-->接收用户的登录请求(获取用户登录的参数,username、password)-->交给业务层处理登录业务(判断用户名和密码是否正确)-->Dao层查询用户名和密码是否正确-->数据库 响应就是上边的逆向
9. Filter(重点)
Filter:过滤器,用来过滤网站的数据
-
处理中文乱码
-
登录验证......
Filter开发步骤:
项目准备阶段编写好后,编写Filter
-
实现Filter接口
注意:导包不要错
-
编写过滤器代码
package com.zcc.filter; import javax.servlet.*; import java.io.IOException; //过滤器 public class FirstFilter implements Filter { //初始化:web服务器启动,就已经初始化了。随时等待过滤对象出现 public void init(FilterConfig filterConfig) throws ServletException { System.out.println("FirstFilter初始化"); } /* 1. 过滤所有代码 在过滤特定请求的时候会执行 2. 必须要让过滤器继续执行 filterChain.doFilter(servletRequest,servletResponse); 写死的代码 */ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); servletResponse.setContentType("text/html;charset=UTF-8"); System.out.println("FirstFilter执行前"); filterChain.doFilter(servletRequest,servletResponse); System.out.println("FirstFilter执行后"); } //销毁:web服务器关闭的时候。过滤被销毁 public void destroy() { System.out.println("FirstFilter销毁"); } }
-
在web.xml添加过滤器配置
<filter> <filter-name>FirstFilter</filter-name> <filter-class>com.zcc.filter.FirstFilter</filter-class> </filter> <filter-mapping> <filter-name>FirstFilter</filter-name> <url-pattern>/Test/*</url-pattern> </filter-mapping>
-
Servlet编码略
-
运行测试:
10. 监听器
以统计网站在线人数为例:
-
编写监听器类,实现对应接口
package com.zcc.listener; import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; //监听器:实现统计网站在线人数为例 (统计session) public class FirstListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent httpSessionEvent) { //创建session监听 查看一举一动 //一旦创建session就会触发这个事件 ServletContext servletContext = httpSessionEvent.getSession().getServletContext(); System.out.println(httpSessionEvent.getSession().getId()); Integer onlineCount = (Integer) servletContext.getAttribute("onlineCount"); if (onlineCount==null){ onlineCount=new Integer(1); }else { int count=onlineCount.intValue(); onlineCount=new Integer(count+1); } servletContext.setAttribute("onlineCount",onlineCount); } public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { //创建session监听 查看一举一动 //一旦销毁session就会触发这个事件 ServletContext servletContext = httpSessionEvent.getSession().getServletContext(); Integer onlineCount = (Integer) servletContext.getAttribute("OnlineCount"); if (onlineCount==null){ onlineCount=new Integer(0); }else { int count=onlineCount.intValue(); onlineCount=new Integer(count-1); } servletContext.setAttribute("onlineCount",onlineCount); } }
-
在web.xml添加编写的监听器
<listener> <listener-class>com.zcc.listener.FirstListener</listener-class> </listener>
-
运行测试,在index.jsp可看到 用其他浏览器打开可增加在线人数
需要注意:第一次运行项目,tomcat会获取多个session,所以,在线人数不是1,而是大于1,所以,要Redeploy一下,重新访问网站,就可以了
11. Fiter 实现权限拦截
以登录注销为例: 流程
-
登录页面 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form action="/L/Login" method="post"> 用户名:<input type="text" name="username"> <br> <input type="submit"> </form> </body> </html>
-
另外设置保存session常量
package com.zcc.util; public class Constant { public static String USER_SESSION="USER_SESSION"; }
-
编写登录的servlet
package com.zcc.servlet; import com.zcc.util.Constant; 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 Login extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); req.getSession().setAttribute(Constant.USER_SESSION,req.getSession().getId()); if (username.equals("admin")){ resp.sendRedirect("/jsp/success.jsp"); }else { resp.sendRedirect("/error.jsp"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
-
编写登录成功、错误页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>success</h1> <a href="/L/Logout">注销</a> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <p>错误页面</p> <a href="login.jsp">返回登录页面</a> </body> </html>
-
编写注销的servlet
package com.zcc.servlet; import com.zcc.util.Constant; 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 Logout extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Object user_session = req.getSession().getAttribute(Constant.USER_SESSION); if (user_session!=null){ req.getSession().removeAttribute(Constant.USER_SESSION); resp.sendRedirect("/login.jsp"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
-
web.xml注册 登录、注销的Servlet
<servlet> <servlet-name>Login</servlet-name> <servlet-class>com.zcc.servlet.Login</servlet-class> </servlet> <servlet-mapping> <servlet-name>Login</servlet-name> <url-pattern>/L/Login</url-pattern> </servlet-mapping> <servlet> <servlet-name>Logout</servlet-name> <servlet-class>com.zcc.servlet.Logout</servlet-class> </servlet> <servlet-mapping> <servlet-name>Logout</servlet-name> <url-pattern>/L/Logout</url-pattern> </servlet-mapping>
-
编写过滤器
package com.zcc.filter; import com.zcc.util.Constant; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class Filter implements javax.servlet.Filter { public void init(FilterConfig filterConfig) throws ServletException { System.out.println("进入"); } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; Object user_session = request.getSession().getAttribute(Constant.USER_SESSION); if (user_session==null){ response.sendRedirect("/login.jsp"); } filterChain.doFilter(servletRequest,servletResponse); } public void destroy() { System.out.println("结束"); } }
-
在web.xml注册Filter
<filter> <filter-name>Filter</filter-name> <filter-class>com.zcc.filter.Filter</filter-class> </filter> <filter-mapping> <filter-name>Filter</filter-name> <url-pattern>/jsp/*</url-pattern> </filter-mapping>
运行测试即可
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具