JSP

416 阅读11分钟

JSP简介

JSP:Java Server Page,java服务器页面,是一个简化的Servlet设计。是在html中嵌入java代码。在执行时会被翻译为Servlet,然后编译执行。

Servlet的缺点: (1)Servlet需要进行配置,不方便维护;(2)Servlet很难向网页中输出HTML页面内容;

JSP一般作为请求发起页面,例如显示表单,超链接;或者作为请求结束页面,例如显示数据。

而Servlet作为请求中处理数据的环节。

image.png

运行结果:

image.png

JSP和Servlet分工案例

jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/web_test2_war_exploded/AServlet" method="post">
        整数1:<input type="text" name="num1"> <br>
        整数1:<input type="text" name="num2"> <br>
        <input type="submit" value="提交">
    </form>
</body>
</html>

Servlet计算:

public class AServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int number1 = Integer.parseInt(req.getParameter("num1"));
        int number2 = Integer.parseInt(req.getParameter("num2"));
        int sum = number1 + number2;
        // 保存结果到request域中
        req.setAttribute("result", sum);
        // 转发到result.jsp
        req.getRequestDispatcher("/jsp/result.jsp").forward(req, resp);
    }
}

内容展示:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%= request.getAttribute("result") %>
</body>
</html>

JSP运行原理

JSP文件会被服务器翻译成Java文件,会将Java文件编译生成class文件,最后来运行class文件。

JSP脚本元素

JSP = HTML + Java代码 + JSP自身内容

JSP的脚本元素就是在JSP中嵌入Java代码

声明标签(!)

语法:(写在这个脚本中的代码,会翻译成Servlet内部的成员变量或成员方法

<%! 变量或方法声明 %>

<%!
    // 声明变量
    int i = 3;
%>

表达式标签(=)

语法:(写在这个脚本中的代码,会翻译成方法内部的out.print()当中的内容

<%= 表达式 %>

<%= i+1 %>

程序代码标签(▲)

语法:(写在这个脚本中的代码,会翻译成方法内部的局部变量或代码片段

<% 程序代码 %>

<%
    int x = 5;
%>
<%= x %>

JSP指令元素

用于指示JSP执行的某些步骤、用于指示JSP表现的特定行为

语法:

<%@ 指令名称 属性名称=属性值 属性名称=属性值 ... %>

指令的分类:

  • page指令:指示JSP页面的设置的属性和行为
  • include指令(静态包含):指示JSP包含哪些其他的页面
  • taglib指令(导入标签库):指示JSP页面要包含哪些标签库

page指令

page属性用来定义JSP文件的全局属性

这些属性是可以单独使用的,也可以多个同时使用。

在JSP页面中,只有import属性可以出现多次,其他属性都只能出现一次。

写法:

<%@ page 属性名称=属性值 属性名称=属性值 ...%>

Page指令属性:

  • language:声明所使用的脚本语言,只能是Java
  • extends:标明JSP编译成Servlet的时候所继承的类。默认值:"HttpJspBase"
  • session:标明JSP中是否可以直接使用Session对象。默认值就是true
  • buffer:标明JSP对客户端输出缓冲区的大小。默认值是8k
  • autoFlush:如果缓冲区大小溢出了,是否会自动刷出。默认值是true
  • import:导入Java的包或类(重要)
  • contentType: 标明JSP被浏览器解析和打开的时候,采用的默认的字符集。它表示添加一个响应头:Content-Type!等同与 response.setContentType("text/html;charset=utf-8");
  • pageEncoding: JSP文件及JSP翻译后的Servlet保存到硬盘上所采用的字符集
  • isErrorPage:处理JSP页面异常,它指定当前页面是否为处理错误的页面!当该属性为 true 时,这个页面会设置状态码为 500!可以使用内置对象exception。
  • errorPage:处理JSP页面异常,当前页面如果抛出异常,那么要转发到哪一个页面,由 errorPage来指定
  • isElIgnore:通知JSP是否忽略EL表达式,默认false不忽略
  • info :JSP说明性信息;

例子:

<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" session="true"
	errorPage="error.jsp" isElIgnore="false"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%
		session.setAttribute("key", "value");
		List list = null;
		ArrayList arrayList = null;
		// int i = 1/0;
	%>
</body>
</html>

include指令

作用:在JSP页面中去静态包含一个文件,同时由该JSP解析包含的文件内容(一起被翻译成servlet)

写法:

<%@ include 属性名称=属性值 属性名称=属性值 ...%>

include指令属性:

  • file:指示JSP页面所包含的页面的路径

例子:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%@ include file="logo.jsp" %>
	<%@ include file="menu.jsp" %>
	<h1>index.jsp 的 BODY 部分</h1>
</body>
</html>

taglib指令

作用:用于在JSP页面中引入标签库

写法:

<%@ taglib 属性名称=属性值 属性名称=属性值 ...%>

taglib指令属性:

  • uri:引入的标签库的路径
  • prefix:引入的标签库的别名

JSP的内置对象

JSP内置对象:指的是可以直接在JSP页面中使用的对象(无需创建)。

在Javaweb中一共四个域对象,其中Servlet中可以使用的是request、session、application三个对象。

而在JSP中可以使用pageContext、request、session、application四个域对象。

内置对象分类

内置对象分类:

  1. request【HttpServletRequest】:从客户端向服务器发送的请求对象
  2. response【HttpServletResponse】:从服务器端向客户端浏览器做出的响应对象
  3. session【HttpSessionre】:服务器为客户端创建的会话对象
  4. application【ServletContext】:代表整个应用,实际是获得的ServletContext对象(一个应用只有一个)
  5. out【JspWriter】:等同response.getWriter(),向输出流写入内容的对象
  6. page【Object】:当前的JSP被翻译成Servlet后的对象的引用
  7. pageContext【PageContext】: 当前的JSP页面的上下文对象
  8. config【ServletConfig】:本JSP的ServletConfig对象
  9. exception【Throwable】:表示JSP页面所运行时产生的异常对象

PageContext对象

pageContext:页面上下文对象,代表当前页面运行的一些属性。包路径:javax.servlet.jsp.PageContext

作用:

  • 提供了page范围的数据存取的方法;
    • getAttribute()
    • setAttribute()
    • removeAttribute()
    • findAttribute() :全局查找,四大域查找
  • 通过这个对象获得其他的8个内置对象;
    • getXXX()--对应对象
    • getOut()--父类中

JSP四个作用范围

  • PageScope:页面范围
    • 指的是当前页面范围内有效,出了这个页面后pageContext保存的数据就无效了
  • RequestScope:请求范围
    • 从客户端向服务器发送一次请求,服务器对这次请求做出响应之后,用request保存的数据就无效了
  • SessionScope:会话范围
    • 每个浏览器向服务器发送请求(可以多次请求),将该会话结束后,保存的数据就无效了
  • ApplicationScope:应用范围
    • 在整个应用任意的地方都可以获取。

例子:

<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>JSP的四个作用范围</h1>
    <%
        // page范围(pageContext对象)
        pageContext.setAttribute("name", "pageContext-张三");
        // request范围
        request.setAttribute("name", "request-李四");
        pageContext.setAttribute("name", "request-李四", PageContext.REQUEST_SCOPE);
        // session范围
        session.setAttribute("name", "session-王五");
        pageContext.setAttribute("name", "session-王五", PageContext.SESSION_SCOPE);
        // application范围
        application.setAttribute("name", "application-赵六");
        pageContext.setAttribute("name", "application-赵六", PageContext.APPLICATION_SCOPE);
    %>

    <h1>当前页面获取值(四种都有效)</h1>
    <%= pageContext.getAttribute("name") %>
    <%= request.getAttribute("name") %>
    <%= pageContext.getAttribute("name", PageContext.REQUEST_SCOPE) %>
    <%= session.getAttribute("name") %>
    <%= pageContext.getAttribute("name", PageContext.SESSION_SCOPE) %>
    <%= application.getAttribute("name") %>
    <%= pageContext.getAttribute("name", PageContext.APPLICATION_SCOPE) %>

<%--    <!-- 转发到demo2.jsp,3种可以生效(request+session+application) -->--%>
<%--    <% request.getRequestDispatcher("/jsp/demo2.jsp").forward(request, response); %>--%>

    <!-- 请求跳转到demo2.jsp,2种可以生效(session+application) -->
    <a href="/web_test2_war_exploded/jsp/demo2.jsp">请求跳转demo2.jsp</a>

</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>demo2.jsp   当前页面获取值(三种有效)</h1>
    <%= pageContext.getAttribute("name") %>   <%--null--%>
    <%= request.getAttribute("name") %>
    <%= session.getAttribute("name") %>
    <%= application.getAttribute("name") %>
</body>
</html>

JSP动作标签

JSP动作标签:用于在JSP页面中提供业务逻辑功能,避免在JSP页面中直接编写Java代码。

动作标签

<jsp:forward/>:请求转发,与RequestDispatcher.forward()方法一致

<jsp:include/>:包含(动态包含,与RequestDispatcher的include方法一样)

<jsp:param/>:传递参数

例子:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>JSP Demo3</title>
</head>
<body>
    <h1>jsp:forward  请求转发</h1>
<%--    <jsp:forward page="demo4.jsp"></jsp:forward>--%>

    <h1>jsp:include  包含</h1>
    <jsp:include page="demo4.jsp"></jsp:include>
</body>
</html>

动态包含的原理:

image.png

JavaBean相关标签

  • <jsp:useBean> --> 创建或查询bean
  • <jsp:setProperty> --> 给JavaBean设置属性值
  • <jsp:getProperty> --> 获取属性值
<jsp:useBean id= "user1" class= "cn.itcast.domainUser" />
<jsp:setProperty property= "username" name="user1" value= "admin"/>
<jsp:setProperty property= "passvord" name= "user1" value="admin123"/>`

用户名:
<jsp:getProperty property= "username" name= "user1"/><br/>

密码:
<jsp:getProperty property= "passvord" name="user1"/><br/>

EL表达式语言

概述

EL(Expression Language)表达式语言, 是为了使JSP写起来更加简单。它提供了在JSP中简化表达式的方法,让Jsp的代码更加简化。EL可以和JSTL一起使用,取代JSP页面中嵌入Java代码的写法(<%%>)。功能:

  • 获取数据
  • 执行运算
  • 获取web开发常用对象
  • 调用Java中的方法(少)

EL 替代的是<= ... >,也就是说,EL只能做输出

EL语法:

${ EL表达式 }

获取数据

EL表达式在执行的时候,会调用pageContext.getAttribute()方法,分别从四个范围查找对应的对象,找到返回对象,找不到返回""(空字符串)

顺序:pageContext > request > response > application

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>EL获取数据</h1>
    <%
        pageContext.setAttribute("name", "张三");
        // request.setAttribute("name", "李四");
        session.setAttribute("name", "王五");
        application.setAttribute("name", "赵六");
    %>

    <%= pageContext.getAttribute("name") %> - ${ pageScope.name } <br>
    <%= request.getAttribute("name") %> - ${ requestScope.name } <br> <%--null--%>
    <%= session.getAttribute("name") %> - ${ sessionScope.name } <br>
    <%= application.getAttribute("name") %> - ${ applicationScope.name } <br>

    <h1>EL简写</h1>
    ${ name } <%--张三--%>
</body>
</html>

获取数组和集合中的数据

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>EL获取数组中的数据</h1>
    <%
        String[] arrs = {"aaa", "bbb", "ccc"};
        pageContext.setAttribute("arrs", arrs);
    %>
    ${ arrs[0] } <%--aaa--%>
    ${ arrs[1] } <%--bbb--%>
    ${ arrs[2] } <%--ccc--%>
    ${ arrs[3] } <%--空--%>

    <h1>EL获取List集合中的数据</h1>
    <%
        List<String> list = new ArrayList<>();
        list.add("111");list.add("222");list.add("333");
        pageContext.setAttribute("list", list);
    %>
    ${ list[0] }
    ${ list[1] }
    ${ list[2] }
    ${ list[3] } <%--空--%>

    <h1>EL获取Map集合中的数据</h1>
    <%
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("aaa", 111);
        map.put("bbb", 222);
        map.put("ccc", 333);
        pageContext.setAttribute("map", map);
    %>
    ${ map.aaa }
    ${ map.bbb }
    ${ map.ccc } <%--333--%>
    ${ map["ccc"] } <%--333--%>
</body>
</html>

执行运算

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        pageContext.setAttribute("n1", 10);
        pageContext.setAttribute("n2", "20");
        pageContext.setAttribute("n3", 30);
        pageContext.setAttribute("n4", 40);
    %>
    <h1>EL执行算数运算</h1>
    ${ n1+n2 } <%--30--%>
    ${ n2-n1 } <%--10--%>
    <h1>EL执行关系运算</h1>
    ${ n1==n2 } <%--false--%>
    ${ n1 eq n2 } <%--false--%>
    ${ n1 < n2 } <%--true--%>
    ${ n1 lt n2 } <%--true--%>
    ${ n1 > n2 } <%--false--%>
    ${ n1 gt n2 } <%--false--%>
    <h1>EL执行逻辑运算</h1>
    ${ (n1<n2) && (n3<n4) } <%--true--%>
    ${ (n1<n2) and (n3<n4) } <%--true--%>
    <h1>EL执行三元运算</h1>
    ${ n1<n2 ? "n1小于n2" : "n1大于n2" } <!-- n1小于n2 -->
    <h1>空运算符</h1>
    ${ empty user } <%--true--%>
    ${ not empty user } <%--false--%>
</body>
</html>

获取web开发常用对象

  • pageContext:相当于JSP内置对象中的 pageContext
    • 作用1:向四个域中存入对象
    • 作用2:获得其他的8个内置对象
  • pageScore:获取指定域下的名称的数据
  • requestScore :获取指定域下的名称的数据
  • sessionScore :获取指定域下的名称的数据
  • applicationScore :获取指定域下的名称的数据
  • param:在页面中接收请求参数(接收一个名称对应一个值的参数)
  • paramValues :在页面中接收请求参数(接收一个名称对应多个值的参数)
  • header:在页面上获取请求头(一个key对应一个value头)
  • headerValues: 在页面上获取请求头 (一个key对应多个value头)
  • cookie:获得cookie中的数据-名称和值
  • initParam:获得全局初始化参数的值
<body>
    <h1>EL获取web开发常用对象-param</h1>
    ${ param.name }
    ${ paramValues.hobby[0] }
    ${ paramValues.hobby[1] }

    <h1>EL获取web开发常用对象-header</h1>
    ${ header["User-Agent"] }

    <h1>EL获取web开发常用对象-cookie</h1>
    ${ cookie.key.name }
    ${ cookie.key.value }
</body>
image.png

pageContext.request.contextPath : 获取项目名

EL函数库

导入标签库: <%@ tablib prefix="fn" uri=http://java.sun.com/jsp/jst1/functions%>

  • string toUppercase (String input):把参数转换成大写
  • String toLowercase (String input):把参数转换成小写
  • int indexOf(String input,String substring):从大串,输出小串的位置
  • boolean contains(String input,String substring):查看大串中是否包含小串
  • boolean containsIgnoreCase(String input,String substring):忽略大小写的,是否包含
  • boolean startsWith(String input,string substring):是否以小串为前缀
  • boolean endsWith(String input,String substring):+是否以小串为后缀
  • String substring (String input,int beginIndex,int endIndex):截取子串
  • String substringAfter(String input,String substring):获取大串中,小串所在位置后面的字符串
  • substringBefore(String input,String substring):获取大串中,小串所在位置前面的字符串
  • string escapeXml(String input):把input中"<"、">"、"&"、"'"、""",进行转义
  • string trim (String input) :去除前后空格
  • String replace(String input,String substringBefore,String substringAfter):替换
  • String[] split(String input,String delimiters):分割字符串,得到字符串数组
  • int length(Object obj):可以获取字符串、数组、各种集合的长度
  • String join(String array[],String separator):联合字符串数组
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        String[] strs = {"a", "b", "c"};
        List list = new ArrayList();
        list.add("aaa");

        pageContext.setAttribute("arr", strs);
        pageContext.setAttribute("list", list);
    %>
    ${ fn:length(arr) } <br> <%--3--%>
    ${ fn:length(list) } <br> <%--1--%>
    ${ fn:toLowerCase("Hello") } <br> <%--hello--%>
    ${ fn:toUpperCase("Hello") } <br> <%--HELLO--%>
    ${ fn:contains("abc", "a") } <br> <%--true--%>
    ${ fn:containsIgnoreCase("abc", "A") } <br> <%--true--%>
    ${ fn:endsWith("Hello.java", ".java") } <br> <%--true--%>
    ${ fn:startsWith("hello", "Hel") } <br> <%--false--%>
    ${ fn:indexOf("Hello-World", "Wo") } <br> <%--6--%>
    ${ fn:join(arr, ";") } <br> <%--a;b;c--%>
    ${ fn:replace("Hello-World", "-", "+") } <br> <%--Hello+World--%>
    ${ fn:join(fn:split("a;b;c", ";"), "-") } <br> <%-- a-b-c --%>
    ${ fn:substring("0123456789", 6, 9) } <br> <%--678--%>
    ${ fn:substring("0123456789", 5, -1) } <br> <%--56789--%>
    ${ fn:substringAfter("Hello-World", "-") } <br> <%--World--%>
    ${ fn:substringBefore("Hello-World", "-") } <br> <%--Hello--%>
    ${ fn:trim("a b c") } <br> <%--a b c--%>
    ${ fn:escapeXml("<html></html>") } <br> <%--<html></html>--%>
</body>
</html>

EL自定义函数库

JSTL标签库

JSTL(Java server pages standarded tag library,即JSP标准标签库),是apache对EL表达式的扩展,一个标准通用的标签库。可以利用这些标签取代JSP页面上的Java代码。

标签库:

  • c标签(core标签库)
  • fmt标签(格式化的标签库)
  • xml标签(xml 标签库,过时了)
  • sql标签(数据库标签库,过时了)
  • JSTL函数库(EL函数)

基本使用

jar包下载地址:www.runoob.com/jsp/jsp-jst…

放入WEB-INF下面的lib文件夹中。然后引入标签库:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

代码:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <% pageContext.setAttribute("name1", "haha"); %>
    ${ name1 }
    <!-- JSTL写法 -->
    <c:set value="hahaha" var="name2" scope="page"></c:set>
    ${ name2 }
</body>
</html>

core标签库常用标签

  • <c:out>:输出
    • value:可以是字符串常量,也可以是EL表达式
    • default:当要输出的内容为null时,会输出default指定的值
    • escapeXml::默认值为true,表示转义。为false时不会转换<和>
  • <c:set>:设置(创建域的属性)
    • var:变量名
    • value:变量值,可以是EL表达式
    • scope:域,默认为page,可选值:page、request、session、application
  • <c:remove>:删除域变量
    • var:变量名
    • scope:要删除哪个域里面的。如果不给出,默认删除所有域中的该名称的变量
  • <c:url>:输出url、把url保存到域中
    • value:指定一个路径。它会在路径前面自动添加项目名
    • <c:param>子标签:用来给url后面添加参数
    • var:指定变量名,一旦添加了这个属性,那么 url 标签就不会再输出到页面,而是把生成的 url 保存到域中
    • scope:它与 var 一起使用,用来保存 url
  • <c:if>:test为真时,执行标签体内容
    • test 属性:条件(Boolean类型的值)
    • var 属性:将test中条件的值赋值给一个变量,在var中定义变量
    • scope属性:作用范围
  • <c:choose>:when标签的test为true时,会执行这个when的内容
    • when
    • otherwise
  • <c:forEach>:用来循环遍历数组、集合,还可以用计数方式来循环
    • 用计数方式来循环
      • var:循环变量
      • begin:设置循环变量从几开始。
      • end:设置循环变量到几结束。
      • step:设置步长!等同于 Java 中的 i++,或 i+=2。Step 默认值为1
    • 用来输出数组、集合
      • items:指定要循环谁,它可以是一个数组或一个集合。
      • var:把数组或集合中的每个元素赋值给var指定的变量。

例子:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <% pageContext.setAttribute("name1", "name1"); %>
    ${ name1 } <br>  <%--name1--%>
    <c:set value="name2" var="name2" scope="page"></c:set>
    ${ name2 } <br> <%--name2--%>

    <% request.setAttribute("code1", "<script>alert('hello');</script>"); %>
    ${ code1 } <%--alert弹窗--%>
    <c:out value="${code1}"></c:out> <%--<script>alert('hello');</script>--%>
    <c:out value="${code1}" escapeXml="false"></c:out> <%--alert弹窗--%>
    <hr>

    <%
        pageContext.setAttribute("a", "pageContext");
        request.setAttribute("a", "request");
        session.setAttribute("a", "session");
        application.setAttribute("a", "application");
    %>
    <c:remove var="a" scope="page" />
    <c:out value="${a}" default="none"/> <br> <%--request(因为pageContext已经被删除了)--%>
    <c:remove var="a"/>
    <c:out value="${a}" default="none"/> <br> <%--none--%>
    <hr>

    <c:url value="/jsp/demo3.jsp" /> <br> <%--/web_test3_war_exploded/jsp/demo3.jsp--%>
    <c:url value="/jsp/demo3.jsp" var="url" scope="request"/> <br>
    <c:out value="${ url }"/> <br>
    <c:url value="/LoginServlet"> <br> <%--/web_test3_war_exploded/LoginServlet?username=abc&password=123--%>
        <c:param name="username" value="abc"/>
        <c:param name="password" value="123"/>
    </c:url> <hr>

    <c:set var="ifvar" value="hello"/>
    <c:if test="${ not empty ifvar }">
        <c:out value="${ ifvar }"/> <%--hello--%>
    </c:if> <hr>

    <c:set var="score" value="${ param.score }"/>
    <c:choose>
        <c:when test="${ score>100 || score<0 }">错误的分数:${score}</c:when>
        <c:when test="${score >=80}">优秀</c:when>
        <c:when test="${score >=60}">及格</c:when>
        <c:otherwise>不及格</c:otherwise>
    </c:choose>
</body>
</html>

if标签

if标签的属性:

  • test 属性:条件
  • var 属性:将test中条件的值赋值给一个变量,在var中定义变量
  • scope属性:作用范围
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>JSTL的if标签</h1>
	<c:set var="i" value="5" scope="page"></c:set>
	<c:if test="${ i>=10 }">
		<font color="red">i大于等于10</font>
	</c:if>
	<c:if var="flag" test="${ i<10 }" scope="page">
		<font color="blue">i小于10</font>
	</c:if>
	<c:if test="${ flag }">
		<font color="blue">i小于10</font>
	</c:if>
</body>
</html>

foreach标签

<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@page import="com.sun.corba.se.spi.orb.StringPair"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>JSTL的foreach标签</h1>
	
	<h3>遍历数组</h3>
	<% 
		String[] arrs = {"aaa", "bbb", "ccc"};
		pageContext.setAttribute("arrs", arrs);
	%>
	<c:forEach var="s" items="${ arrs }">
		${ s }
	</c:forEach>
	
	<h3>遍历List集合</h3>
	<%
		List<String> list = new ArrayList<String>();
		list.add("qqq");list.add("www");list.add("eee");
		pageContext.setAttribute("list", list);
	%>
	<c:forEach var="s" items="${ list }">
		${ s }
	</c:forEach>
	
	<h3>遍历Map集合</h3>
	<%
		Map<Integer, String> map = new HashMap<Integer, String>();
		map.put(1, "1111");map.put(2, "2222");map.put(3, "3333");
		pageContext.setAttribute("map", map);
	%>
	<c:forEach var="entry" items="${ map }">
		${ entry }  <!-- 1=1111 2=2222 3=3333 -->
	</c:forEach>
	
	<h3>遍历1-10</h3>
	<c:forEach var="i" begin="1" end="10" step="1">
		${ i }
	</c:forEach>
	
	<h3>遍历100-200  到第三个数,数字变为蓝色</h3>
	<c:forEach var="i" begin="100" end="200" step="2" varStatus="status">
		<c:if test="${ status.count%3 ==0 }">
			<font color="blue">${ i }</font>
		</c:if>
		<c:if test="${ status.count%3 !=0 }">
			<font>${ i }</font>
		</c:if>
	</c:forEach>
</body>
</html>

foreach循环状态变量

forEach 标签还有一个属性: varStatus,这个属性用来指定接收“循环状态“的变量名,例如:<forEach varStatus="vs" …/>,这时就可以使用vs这个变量来获取循环的状态。

  • count:int 类型,当前已遍历元素的个数;
  • index:int 类型,当前元素的下标;
  • first:boolean类型,是否为第一个元素;
  • last:boolean类型,是否为最后一个元素;
  • current:Object 类型,表示当前项目。
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        ArrayList list = new ArrayList<String>();
        list.add("1⃣️一一一");
        list.add("2⃣️二二二");
        list.add("3⃣️三三三");
        pageContext.setAttribute("list", list);
    %>
    <c:forEach items="${list}" var="element" varStatus="vs">
        ${element},当前已遍历元素的个数:${vs.count},当前元素的下标:${vs.index},
        当前是否是第一个:${vs.first},当前是否是最后一个:${vs.last}。当前元素是:${vs.current}
        <br>
    </c:forEach>
</body>
</html>

fmt格式化标签

用来格式化输出的,通常需要格式化的有时间和数字

  • 格式化时间
    • value:指定一个Date类型的变量
    • pattern:用来指定输出的模板!例如:yyyy-MM-dd HH:mm:ss
  • 格式化数字
    • 0.00 四舍五入,且以0进行补位
    • #.## 四舍五入,不补位
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        Date date = new Date();
        pageContext.setAttribute("date", date);
    %>
    <fmt:formatDate value="${date}" pattern="yyyy-MM-dd HH:mm:ss" /> <br> <%--2022-10-03 16:34:28--%>

    <%
        double d1 = 3.1415926;
        double d2 = 4.4;
        pageContext.setAttribute("d1", d1);
        pageContext.setAttribute("d2", d2);
    %>
    <fmt:formatNumber value="${d1}" pattern="0.000"/> <br> <%--3.142--%>
    <fmt:formatNumber value="${d2}" pattern="0.000"/> <br> <%--4.400--%>
    <fmt:formatNumber value="${d1}" pattern="#.###"/> <br> <%--3.142--%>
    <fmt:formatNumber value="${d2}" pattern="#.###"/> <br> <%--4.4--%>
</body>
</html>

MVC开发模式

动态网页开发模式

开发模式不同阶段缺点/优点
第一阶段:Servlet缺点:显示HTML元素时非常麻烦
第二阶段:JSP优点:显示数据方便;缺点:数据的封装和处理
第三阶段:JSP+JavaBean优点:显示数据和封装数据方便;缺点:维护麻烦
第四阶段:JSP+Servlet+JavaBean优点:JSP显示数据、JavaBean封装和处理数据、Servlet控制调度

JSP+Servlet+JavaBean,称为MVC开发模式。MVC解释如下:

  • M(Model):模型层
  • V(View):视图层
  • C(Controller):控制层

流转链路:

请求 --> Servlet(控制层)--> JavaBean(模型层)--> JSP(视图层)

Request作为域对象存取数据

作用范围: Request对象中所保存的数据有效期是一次请求范围

一次请求范围:从浏览器向服务器发送一次请求,服务器针对这次请求做出响应,响应后请求被销毁,保存的数据就失效了。

请求转发 & 重定向

请求转发:

  1. 通过ServletRequest对象获得RequestDispatcher对象;
  2. 根据RequestDispatcher中的forward()方法进行请求的转发;

重定向:

  1. 使用HttpServletResponse里面的sendRedirect()方法实现重定向;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 方式1:请求转发
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/demo3/dem1.jsp");
        requestDispatcher.forward(request, response);
		
        // 方式2:重定向
        response.sendRedirect("/web02/demo3/demo1.jsp");
}

两者区别:

  • 请求转发是一次请求一次响应,而重定向是两次请求两次响应
  • 请求转发地址栏是不会变化的,重定向地址栏发生变化
  • 请求转发路径不带工程名,重定向需要带工程名路径
  • 请求转发只能在本网站内部,重定向可以定向到任意网站

如果需要使用request进行值传递,需要通过请求转发完成;

如果页面需要跳转到其他网站,必须要使用重定向完成;

image.png

实践案例1(登录)

1、需求分析

需求:

  • 提供登录页面,用户名密码查询数据库;
  • 登录失败时回到登录页面(给提示信息);
  • 登录成功,页面跳转,显示登录成功的总人数;

2、准备:创建库表

create database web_test;
use web_test;

create table user2(
	uid int primary key auto_increment,
	username varchar(20),
	password varchar(20),
	nickname varchar(20)
);

insert into user2 values (null, 'zhangsan', '123', '张三');
insert into user2 values (null, 'lisi', '123', '李四');
insert into user2 values (null, 'wangwu', '123', '王五');
image.png

3、创建项目工程

image.png

4、引入相关资源

数据库驱动包、C3P0连接池jar包、DBUtils

image.png

C3P0配置文件:

image.png

工具类:

package com.login.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBCUtils {
    // 创建一个连接池,只需要创建一次即可
    private static final ComboPooledDataSource dataSource = new ComboPooledDataSource();

    /**
     * 获得连接的方法
     */
    public static Connection getConnection() {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return connection;
    }

    public static DataSource getDataSource() {
        return dataSource;
    }

    /**
     * 释放资源的方法
     */
    public static void release(Statement statement, Connection connection) {
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            statement = null;
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            connection = null;
        }
    }

    public static void release(Statement statement, Connection connection, ResultSet resultSet) {
        release(statement, connection);
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            resultSet = null;
        }
    }
}

5、登录实现

登录流程:

登录页面(login.jsp)->登录的Servlet(LoginServlet,接收数据,封装到JavaBean)->调用另一个JavaBean处理数据,根据处理结果进行页面跳转

登录页面:

<%--
  Created by IntelliJ IDEA.
  User: wanghao39
  Date: 2022/9/18
  Time: 下午1:41
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>$Title$</title>
</head>
<body>
    <h1>登录页面</h1>
    <%
        String msg = "";
        // 判断request域中是否存在错误信息
        if (request.getAttribute("msg") != null) {
            msg = (String) request.getAttribute("msg");
        }
    %>

    <h3><%= msg %></h3>

    <form action="/web_login_war_exploded/LoginServlet" method="post">
        <table border="1" width="400">
            <tr>
                <td>用户名</td>
                <td><input type="text" name="username" /></td>
            </tr>
            <tr>
                <td>密码</td>
                <td><input type="password" name="password" /></td>
            </tr>
            <tr>
                <td colspan="2"><input type="submit" value="登录" /></td>
            </tr>
        </table>
    </form>
</body>
</html>

登录Servlet:

package com.login.controller;

import com.login.domain.User;
import com.login.model.UserModel;

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 LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            // 接收数据
            req.setCharacterEncoding("UTF-8");
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            // 封装数据
            User user = new User();
            user.setUsername(username);
            user.setPassword(password);
            // 处理数据
            UserModel userModel = new UserModel();
            User existUser = userModel.login(user);
            // 页面跳转
            if (existUser == null) {
                // 登录失败,向request域保存失败信息
                req.setAttribute("msg", "用户名或密码错误");
                // 使用请求转发进行页面跳转
                req.getRequestDispatcher("/index.jsp").forward(req, resp);
            } else {
                // 登录成功,记录人数
                int count = (int) this.getServletContext().getAttribute("count") + 1;
                this.getServletContext().setAttribute("count", count);
                // 使用重定向进行页面跳转
                resp.sendRedirect("/success.jsp");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

数据处理:

package com.login.model;

import com.login.domain.User;
import com.login.utils.JDBCUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.sql.SQLException;

public class UserModel {

    public User login(User user) throws SQLException {
        // 处理数据
        QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());
        User existUser = queryRunner.query("select * from user2 where username = ? and password = ?",
                new BeanHandler<User>(User.class), user.getUsername(), user.getPassword());
        return existUser;
    }
}

初始化:

package com.login.controller;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

public class InitServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        int count = 0;
        this.getServletContext().setAttribute("count", count);
    }
}

成功页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>恭喜登录成功!</h1>
    <%
    int count = 0;
    if(request.getServletContext().getAttribute("count") !=null) {
        count = (int)request.getServletContext().getAttribute("count");
    }
    %>
    <h3>目前登录成功总人数:<%=count %></h3>
</body>
</html>

6、实现效果

image.png image.png image.png