Bootstrap

JavaWeb

JavaWeb

1、Servlet工作原理:

先 localhost:8080/javaweb-01/zhang 请求发过来 

服务器接收到请求后,会解析请求的URL路径,访问Servlet的资源路径。

根据这个路径 localhost:8080 找到正在运行的tomcat容器↓

根据idea中tomcat给当前项目配置的虚拟目录 javaweb-01 找部署在tomcat中对应的项目↓

//下面需要打开Servlet项目的web.xml文件对比解读

如果没有虚拟路径或者默认为 / ,跳过上一步直接去找项目下的 web.xml 查找遍历是否有 /zhang 对应的<servlet-mapping>里的<url-pattern>配置,再根据这个配置的同级配置<servlet-name>去找映射的<servlet>配置,最后根据<servlet>下的<servlet-class>里的全类名对应的字节码文件加载到内存中: Class cls= Class.forName(全类名),再创建对象: HelloServlet hs= cls.newInstance(),最后调用service()方法:hs.service。 因为遵守了Servlet的规则,所以会自动调用service()方法↓

最终service方法执行,由开发人员事先实现的操作来处理请求消息和返回内容。

Servlet生命周期:servlet在用户第一次请求时创建,直到服务器关闭才销毁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xydfQXGF-1624634278975)(D:\有道\Text\weixinobU7VjuPiULJulDY7dzNgusLPRY8\4ad93a3487104ece83b8819a52de829f\servlet执行原理.png)]

得出的结论:

Servlet依赖于toncat容器,容器帮Servlet实现方法的调用

xml文件中的<servlet-mapping>中的路径优先级为  单指>多指>/*
ServletContext(上下文/环境共享数据)(后期使用session代替):
ServletContext(上下文),可以实现数据共享,一个Servlet通过创建实例存入一些数据或者节点信息之后,所有的Servlet都可以通过创建ServletContext的实例来拿到这些节点信息

注:存入数据以k-v的方式
ServletContext的方法:

首先 ://获取context对象 :ServletContext context = this.getServletContext();

获取web应用的初始化参数

String gp = context.getInitParameter("url");

//返回的结果:
"jdbc:mysql://localhost:3306:mybatis"
<context-param>
     <param-name>url</param-name>
     <param-value>jdbc:mysql://localhost:3306:mybatis</param-value>
</context-param>
请求转发(后期使用request代替)
//请求转发:传一个目标路径,然后 forward转发把request和response的参数传进去
//这里起到的只是将请求转发的作用
context.getRequestDispatcher("/contexTest").forward(req,resp);
<!--转发的url-->
<servlet>
    <servlet-name>contexTest</servlet-name>
    <servlet-class>com.zsh.servlet.ReaderContext</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>contexTest</servlet-name>
    <url-pattern>/context</url-pattern>
</servlet-mapping>
解释一下转发和重定向的大概意思
假设有 A(客户端) B(1号服务器) C(2号服务器) 这样的关系

转发:
A想去拿一个资源,这个资源只有C有,但是A不知道有C的存在,也就是不知道C有资源和如何访问到C,只能面向B。
B接收到请求之后B做了一件事,把A需要的资源请求转发到C,C接收到请求之后返回资源给B。
B再将资源发送给A,A从头到尾都不知道C的存在

重定向:
A想去拿一个资源,这个资源只有C有,但是A不知道有C的存在,也就是不知道C有资源和如何访问到C,只能面向B。
B接收到请求之后B做了一件事,把A请求的目标变为C,去访问C可以拿到这个资源。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-28IcfCMg-1624634278977)(C:\Users\Administrator\Pictures\QQ浏览器截图\请求和重定向.PNG)]

读取资源文件(Properties)(也不会常用这种方式,代替的方式有 类加载、反射机制等待其他技术)

​ 1)、在java类路径下新建properties

​ 2)、在resources目录下新建properties

发现:每次都被打包到了同一个路径下classes,这个路径称为类路径:classpath

思路:需要一个文件流去读取路径下的文件

//返回InputStream字节输入流
//参数为Resources下的资源路径 \代表当前target下的web应用
//给一个文件流
InputStream stream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
//通过new Properties类来操作 Properties资源文件
Properties prop = new Properties();
prop.load(stream);
//getkey返回value
String s = prop.getProperty("username");
String s2 = prop.getProperty("password");

2、HttpServletResponse

web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象

和一个代表响应的HttpServletResponse;

如果要获取客户端请求过来的参数:找HttpServletRequest

如果要给客户端响应一些信息:找HttpServletResponse

简单分类

负责向浏览器发送数据的方法

//实现父接口获得的方法
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;

负责向浏览器发送响应头的方法

//实现父接口获得的方法
void setCharacterEncoding(String var1);

void setContentLength(int var1);

void setContentLengthLong(long var1);

void setContentType(String var1);

//自己类中的方法
void setDateHeader(String var1, long var2);

void addDateHeader(String var1, long var2);

void setHeader(String var1, String var2);

void addHeader(String var1, String var2);

void setIntHeader(String var1, int var2);

void addIntHeader(String var1, int var2);

void setStatus(int var1);

响应的状态码

int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
//200 = ok
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
//3xx = 请求重定向
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
//400 = 错误的请求
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
//404 = 未找到
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
//500 = 内部服务器错误
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
//502 = 网关错误
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
//504 = 网关超时
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
下载文件
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
    //- 获取下载文件的路径  直接使用绝对路径 写死了??
    String realPath = "D:\\ideaProject\\az\\javaweb-02-servlet\\httpresponse\\target\\classes\\彭于晏.jpg";
    System.out.println("----->"+realPath);
    //- 定义下载的文件名  记住:一个资源路径的最后一位/后面的字符就是请求文件的文件名
    //这行代码的意思是:截取获得的绝对路径最后的 / 后面的字符
    String filename = realPath.substring(realPath.lastIndexOf("/") + 1);
    //- 设置浏览器支持我下载需要的资源 修改字符编码,防止中文名文件下载时出现乱码 也不一定解决
    resp.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(filename,"UTF-8"));
    //- 获取下载文件的输入流 把文件加载到流中
    FileInputStream in = new FileInputStream(realPath);
    //- 创建缓冲区
    int len = 0;
    byte[] buffer = new byte[1024];
    //- 获取response的OutputStream对象
    ServletOutputStream out = resp.getOutputStream();
    //- 将FileOutputStream流写入到buffer缓冲区
    //- 使用OutputStream将缓冲区的数据输出到客户端
    while ((len = in.read(buffer))> 0){
   
        out.write(buffer,0,len);
    }
    //- 关闭流
    out.close();
    in.close();
}
//再去web.xml文件补充servlet信息和映射
//访问下载
//成功!

验证码功能

验证怎么来的?

  1. 前端实现

  2. 后端实现

    这种方法以后基本碰不到,了解一下代码格式流程,大概意思就好

    第一步:需要用到java的图片类,产生一个图片

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         
    
        //让浏览器3秒刷新一次
        resp.setHeader("refresh","3");
    
        //在内存中创建一个图片
        //参数为:宽  高  颜色类型
        BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
        //拿到这张图片,以2d的格式
        Graphics2D graphics = (Graphics2D) image.getGraphics();
        //设置这张图片填充的背景颜色
        graphics.setBackground(Color.WHITE);
        //填充位置 参数:坐标 宽 高
        graphics.setClip(0,0,80,20);
        //字体颜色
        graphics.setColor(Color.red);
        //设置字体样式 第一个节点为null,字体类型,大小
        graphics.setFont(new Font(null,Font.BOLD,20));
        //给图片写入随机数,坐标
        graphics.drawString(makeRandom(),0,20);
        //告诉浏览器,这个请求用图片打开
        resp.setContentType("image/png");
        //网站存在缓存,不让浏览器缓存 这些都是缓存策略
        resp.setDateHeader("expires",-1);
        resp.setHeader("Cache-Control","no-cache");
        resp.setHeader("Pragma","no-cache");
    
        //把图片写到浏览器
        ImageIO.write(image,"png",resp.getOutputStream());
    }
    

    第二步:创建一个随机数类

    //生成随机数作为验证码
    private String makeRandom(){
         
        //先获取随机数的对象
        Random random = new Random();
        //创建指定范围的随机数,加一个空串让这个随机数变为String类型
        String num = random.nextInt(999999) + "";
        //防止出现低于六位数的随机数,计算得到的随机数需要补几个 0
        //i < 6-s.length() 意思是如果拿到的随机数不够六位的 也就是  > 6那就进入循环 sb添加进去一个零,与6相比随机数的length差n<=位就会进入n<6次循环,补的0就有n<=6个
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 6-num.length() ; i++) {
         
            sb.append("0");
        }
    
        num = num + sb.toString();
        return num;
    }
    
    
    
    String random = drawRandomNum((Graphics2D) g,“l”);//生成纯字母的验证码
Response重定向
//需要使用的方法
void sendRedirect(String var1) throws IOException;

//如果这个servlet被访问就会重定向到 /yzm
//记得加上tomcat中设置的项目路径
resp.sendRedirect("/rp/yzm");

/*
剖析一下原理,其实就做了两步
*/
//跳转的路径
resp.setHeader("Location","/rp/yzm");
//状态码,3xx = 请求重定向
resp.setStatus(302);
面试题

请你聊聊重定向和请求转发的区别

相同点:都会实现页面跳转

不同点:
	请求转发的时候,url不会发生变化   header状态码:307
	重定向的时候,url地址栏会发生变化 header状态码:302

3、HttpServletRequest

HttpServletRequest代表用户端的请求,用户通过http协议访问服务器

转发不需要虚拟项目路径,重定向需要

获取前端请求参数,并请求转发
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   

    //设置请求和响应的编码格式,保证不乱码
    req.setCharacterEncoding("utf-8");
    resp.setCharacterEncoding("utf-8");
    //单个接收前端发送的请求
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    String[] hobbies = req.getParameterValues("hobbies");
    //控制台打印
    System.out.println(username);
    System.out.println(password);
    System.out.println(Arrays.toString(hobbies));

    //转发到成功页面
    req.getRequestDispatcher("/success.jsp").forward(req,resp);

}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
    doGet(req, resp);
}

4、cookie,session

逻辑和原理
由于HTTP是一种无状态协议,服务器没有办法单单从网络连接上面知道访问者的身份,为了解决这个问题,就诞生了Cookie

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie

客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,

以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。

实际就是颁发一个通行证,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理

cookie 可以让服务端程序跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些Cookie,如果 Cookie 很多,这无形地增加了客户端与服务端的数据传输量,

而 Session 的出现正是为了解决这个问题。同一个客户端每次和服务端交互时,不需要每次都传回所有的 Cookie 值,而是只要传回一个 ID,这个 ID 是客户端第一次访问服务器的时候生成的, 而且每个客户端是唯一的。这样每个客户端就有了一个唯一的 ID,客户端只要传回这个 ID 就行了,这个 ID 通常是 NANE 为JSESIONID 的一个 Cookie。
源码和工作原理剖析
cookie的内容主要包括name(名字)、value(值)、maxAge(失效时间)、path(路径),domain(域)和secure

name:cookie的名字,一旦创建,名称不可更改。

value:cookie的值,如果值为Unicode字符,需要为字符编码。如果为二进制数据,则需要使用BASE64编码.

maxAge:cookie失效时间,单位秒。如果为正数,则该cookie在maxAge后失效。如果为负数,该cookie为临时cookie,关闭浏览器即失效, 浏览器也不会以任何形式保存该cookie。如果为0,表示删除该cookie。默认为-1

path:该cookie的使用路径。如果设置为"/sessionWeb/",则只有ContextPath为“/sessionWeb/”的程序可以访问该cookie。如果设置为“/”,则本域名下ContextPath都可以访问该cookie。

domain:域.可以访问该Cookie的域名。第一个字符必须为".",如果设置为".google.com",则所有以"google.com结尾的域名都可以访问该cookie",如果不设置,则为所有域名

secure:该cookie是否仅被使用安全协议传输。

Session机制

Session机制是一种服务端的机制,服务器使用一种类似散列表的结构来保存信息。

当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端里的请求里是否已包含了一个session标识--sessionID,

如果已经包含一个sessionID,则说明以前已经为此客户端创建过session,服务器就按照sessionID把这个session检索出来使用

如果客户端请求不包含sessionID,则为此客户端创建一个session并且声称一个与此session相关联的sessionID,

sessionID的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串(服务器会自动创建),这个sessionID将被在本次响应中返回给客户端保存。
两种技术的优弊端or解决方案
使用cookie的缺点

如果浏览器使用的是cookie,那么所有的数据都保存在浏览器端,

cookie可以被用户禁止

cookie不安全(对于敏感数据,需要加密)

cookie只能保存少量的数据(大约是4k),cookie的数量也有限制(大约是几百个),不同浏览器设置不一样,反正都不多

cookie只能保存字符串

对服务器压力小

使用session的缺点

一般是寄生在Cookie下的,当Cookie被禁止,Session也被禁止

当然可以通过url重写来摆脱cookie

当用户访问量很大时,对服务器压力大

我们现在知道session是将用户信息储存在服务器上面,如果访问服务器的用户越来越多,那么服务器上面的session也越来越多, session会对服务器造成压力,影响服务器的负载.如果Session内容过于复杂,当大量客户访问服务器时还可能会导致内存溢出。

用户信息丢失, 或者说用户访问的不是这台服务器的情况下,就会出现数据库丢失.


session销毁
手动销毁
某个对象.getSession.invalidate();
自动销毁
<!--在xml配置session的销毁时间-->
    <session-config>
        <session-timeout>1</session-timeout> //分钟
    </session-config>
cookie和session的区别
具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到, 由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的

cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session

session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie

单个cookie保存的数据不能超过4k,很多浏览器都限制一个站点最多保存20个cookie。

可以将登陆信息等重要信息存放为session。

cookie是把用户的数据写给用户浏览器,浏览器保存(可以多个)

session是把用户的数据写到用户独占的session中,服务端保存(只保存重要的信息,减少资源的浪费),且对象由服务器创建
session-config
session配置
<session-config>
    <cookie-config></cookie-config> cookie配置
    <session-timeout></session-timeout> session超时时间,多久之后过期,单位:分钟
    <tracking-mode></tracking-mode>
</session-config>

5、JSP(Java Server Pages)

jsp : Java服务端页面,也和servlet一样,用于动态web技术!

最大的特点:
  • 写JSP就像在写HTML
  • 区别
    • HTML只给用户提供静态的数据
    • JSP中可以嵌入Java代码,为用户提供动态数据

浏览器向服务器发送请求,不管访问什么资源,其实都是在访问servlet

jsp最终也会被转换为一个java类

jsp本质上就是一个servlet

这是jsp.java中的方法

//初始化
public void _jspInit(){
   
	
}
//销毁
public void _jspDestroy(){
   

}
//JSPService
public void _jspService(.HttpServletRequest req,HttpServletResponse resp){
   
	这个方法中先判断了请求是否错误,然后判断请求为post还是get
}
内置了一些对象
final javax.servlet.jsp.PageContext pageContext;		//页面上下文
javax.servlet.http.HttpSession session = null;			//会话
final javax.servlet.ServletContext application;			//applicationContext 
final javax.servlet.ServletConfig config;				//配置
javax.servlet.jsp.JspWriter out = null;					//写出
final java.lang.Object page = this;						//page = this:代表当前页面
HttpServletRequest req									//请求
HttpServletResponse resp								//响应
//后面还有两个不需要了
输出页面前的代码
response.setContentType("text/html");		//定义响应的页面类型
pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true); 
_jspx_page_context = pageContext;
application = pageContext.getServletContext();  //application 本质上就是 ServletContext
config = pageContext.getServletConfig();		//获取配置对象
session = pageContext.getSession();				//会话对象
out = pageContext.getOut();						//写出对象
_jspx_out = out;							

//以上的对象,在JSP中可以直接使用
访问JSP的整个过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b4FBiTIN-1624634278978)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210331084112199.png)]

JSP页面中:

只要是嵌入在<%这里的代码%>,直接原封不动的用out.write()写到页面

只要是HTML代码,就会转换为out.write(“字符串,这里会自动识别是否需要换行”)写到页面

JSP基础语法

​ 先导入需要的依赖

<dependencies>
    <!--servlet依赖-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>
    <!--jsp依赖-->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.3</version>
    </dependency>
    <!--JSTL表达式依赖-->
    <dependency>
        <groupId>javax.servlet.jsp.jstl</groupId>
        <artifactId>jstl-api</artifactId>
        <version>1.2</version>
    </dependency>
    <!--jsp标签库-->
    <dependency>
        <groupId>taglibs</groupId>
        <artifactId>standard</artifactId>
        <version>1.1.2</version>
    </dependency>

</dependencies>
JSP注释:<%–在这写–%>
JSP表达式:<%= 变量或者表达式%>
<%里面写的Java代码可以分段插入html代码 比如:
for(int i = 0;i<100;i++){
    out.write("111");
%>
<h1>
    你好
</h1>
<%
	out.write("2222");
}
%>

JSP声明:

<%!在这写%>
<%!
写函数的地方,这里写的代码会被编译到类中,其他的会被编译到_jspService方法中
作用域更大,可以写全局方法、变量和静态代码块    
%>

EL表达式:


JSP的注释不会在客户端显示

JSP指令
<%注意%>

这个脚本文件里写的代码片段一定要是Java代码,注释也是,不能出现jsp,html的代码和注释。

因为这个代码片段会被编译成java代码,其他语言的代码在这个片段里被编译之后无法转换为java语法的代码,

定制错误跳转页面
<%--访问到这个页面的时候,错误代码为500时就会跳转到  "error/500.jsp"--%>
<%@ page errorPage="error/500.jsp" %>
<%--显示的声明这是一个错误页面%>
<%@ page isErrorPage="true" %>
xml文件中配置访问错误映射
<error-page>
    <!--接收什么错误代码-->
    <error-code>404</error-code>
    <!--异常类型-->
    <exception-type></exception-type>
    <!--接收到错误之后跳转的位置-->
    <location>/error/500.jsp</location>
</error-page>
9大内置对象
  • PageContext 存东西
  • Request 存东西
  • Response
  • Session 存东西
  • Application 【ServletContext】 存东西
  • Config 【ServletConfig】
  • out
  • Page 不用
  • exception
内置对象的作用域及生命周期
<%--内置对象--%>
<%
pageContext.setAttribute("name1","小张一号");//保存的数据只在一个页面中有效
request.setAttribute("name2","小张二号");//保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name3","小张三号");//保存的数据只在一次会话中有效,生命周期在打开浏览器到关闭浏览器
application.setAttribute("name4","小张四号");//保存的数据在服务器中有效,生命周期从打开服务器到关闭服务器
%>

<%
//从底层到高层(作用域)去查找:Page-->Request--->Session--->Application
String name1 = (String) pageContext.findAttribute("name1");
String name2 = (String) pageContext.findAttribute("name2");
String name3 = (String) pageContext.findAttribute("name3");
String name4 = (String) pageContext.findAttribute("name4");
String name5 = (String) pageContext.findAttribute("name5");//没有这个数据
%>

<%--使用EL表达式输出--%>
<h1>${name1}</h1>
<h1>${name2}</h1>
<h1>${name3}</h1>
<h1>${name4}</h1>
<%--这个不存的数据用两种方式输出--%>

<%--输出结果:什么也没有,空--%>
<h1>${name5}</h1>
<%--输出结果:NULL--%>
<h1><%=name5%></h1>

开启另一个会话再访问(启动另一个浏览器窗口)

<%
String name1 = (String) pageContext.findAttribute("name1");
String name2 = (String) pageContext.findAttribute("name2");
String name3 = (String) pageContext.findAttribute("name3");
String name4 = (String) pageContext.findAttribute("name4");
String name5 = (String) pageContext.findAttribute("name5");//没有这个数据
%>

<h1>${name1}</h1>
<h1>${name2}</h1>
<%--打开新的标签页,取出;打开新的浏览器窗口之后找不带该元素,结果为空--%>
<h1>${name3}</h1>
<%--取出--%>
<h1>${name4}</h1>
<%--空--%>
<h1>${name5}</h1>
<%--NULL--%>
<h1><%=name5%></h1>

结论

request:客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻,用户看完没用的!

session:客户端向服务器发送请求,产生的数据,用户用完一会还有用,比如:购物车;

application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:评论;

重定向前后端方式

Servlet:

request.getRequestDispatcher("路径.jsp/.html/.htm").forward(request,response);

Jsp

pageContext.forward("路径");
JSP标签库(JSTL标签)、EL表达式

使用 JSTL标签 需要引入依赖

<!--JSTL表达式依赖-->
    <dependency>
        <groupId>javax.servlet.jsp.jstl</groupId>
        <artifactId>jstl-api</artifactId>
        <version>1.2</version>
    </dependency>
    <!--jsp标签库-->
    <dependency>
        <groupId>taglibs</groupId
;