1 JSP
- java server page,是一种动态网页技术,可以根据用户请求,生成不同页面
- jsp本质上是servlet,是java类,tomcat会通过jsp引擎将jsp转为servlet,jsp里一般不写业务逻辑
- jsp≈java+html
1.1 JSP与Servlet区别
- servlet
- 逻辑处理方便
- 页面表现麻烦
- jsp
- 页面表现方便
- 逻辑处理麻烦
- 初级web项目,通常采用jsp+servlet+javabean(用于将数据库中数据转为对象),高级项目通常使用SSM框架
1.2 JSP执行过程
- Tomcat收到请求:http://localhost:8080/jsp/1.jsp
- Tomcat根据conf/web.xml中的配置,找到org.apache.jasper.servlet.JspServlet类处理
<!--conf/web.xml-->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
</servlet>
- JspServlet类会根据你的输入的jsp文件名,使用JSP引擎,动态的生成"JSP文件名_jsp.class"与"JSP文件名_jsp.java"文件,并执行class文件
//对于Intellij IDEA文件所在路径如下
C:\Users\含低调\.IntelliJIdea2019.3\system\tomcat\Unnamed_myfirstServletWu\work\Catalina\localhost\myfirstServlet\org\apache\jsp
注:由于JSP对应的java文件,是收到请求时动态生成的,因此修改JSP后,不需要重启Tomcat就能生效,但对于Intellij IDEA需要对Tomcat服务器进行如下设置
1.3 编译器指令:<%@ %>
- 告诉JSP引擎如何将JSP转译成servlet
1.3.1 page
- 用来设置转义成servlet文件时的参数
- 属性
- contentType:表示浏览器解析响应时候使用的编码和解析格式
- language:表示jsp转译成的文件类型
- import:导入需要的jar包,使用逗号分隔
- pageEncoding:设置页面编码格式,设置了他,就可以不设置contentType中的charset,但如果都设置,必须保持一致
- session:用来控制servlet中是否创建session对象
- errorPage:当页面发生逻辑错误时,跳转的页面
- extends:选择要转译的servlet类要继承的父类(包名+类名)
- 示例
...
<%@page contentType="text/html;charset=UTF-8" language="java" import ="java.util.*" pageEncoding="utf-8" %>
<%@page session="false" errorPage="error.jsp" %>
<html>
<head>
<title>Title</title>
</head>
<body>
</body>
</html>
1.3.2 include
- 用于导入另一个jsp页面
- 页面一般头尾都不变,可以将头尾抽象成一个jsp,另一个jsp直接导入该jsp,减少样板代码
- 静态导入:<%@include file=“jsp相对路径”%>
- 不会将静态导入页面生成一个新的servlet文件,而是单纯的将两个文件合并
- 优点:运行效率高
- 缺点:两个页面会耦合到一起,不利于维护,两个页面中不能存在相同名称的变量
- 动态导入:<jsp:include page=“danamic.jsp”></jsp:include>
- 两个页面不会进行合并,分别生成自己的servlet文件,但页面在最终展示的时候是合并到一起的
- 优点:没有耦合,可以存在同名的变量
- 示例
...
<html>
<head>
<base href="<%=basePath%>">
<title>Title</title>
</head>
<body>
<%@include file="static.jsp"%>
<jsp:include page="danamic.jsp"></jsp:include>
</body>
</html>
1.3.3 taglib
- taglib用于导入标签库
- 标签库:指一堆标签
- 标签库描述文件:定义了标签名与java类对应关系的tld文件
- JSP引擎会根据tld文件中的标签名,将其转为对应的java类并进行处理
<%--prefix:表示为标签库设定了一个简短的别名--%>
<%--uri表示要导入的标签库的地址,这个地址指向一个tld文件--%>
<%--tld文件为标签库的描述文件,里面有标签名与java类的对应关系,它告诉服务器如何将这些标签转为java类并进行处理--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
1.4 JSP中嵌入java代码
- 局部代码块:<%%>
- 相当于在service方法中加代码
- 缺点:代码可读性差,开发麻烦。一般不使用
- 全局代码块:<%!%>
- 相当于在servlet类中定义公共的方法
- 可以使用局部代码块对其进行调用
- 脚本调用方法:<%=%>
- 相当于在servlet中生成out.write(变量/方法)这种代码,要求write内的方法必须有返回值,且不能在变量或方法后加";"
- 正常想用out.write打印某个值,直接写汉字即可,但如果想利用out.write打印变量值或打印函数返回值,就需要使用<%=%>
- 示例
...
<%!
String str = "含低调";
public String test(){
return "含低调test";
}
%>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
int i = new Random().nextInt(10);
if(i>5){
%>
//相当于直接调用out.write(“今天天气很好”)
今天天气很好
<%
}else{
//没法直接在jsp中写out.write(test());,因为压根没有response对象,也无法调用它的方法
%>
<%=test()%>
<%}%>
</body>
</html>
1.5 JSP中的请求转发
- <jsp:forward page=“forward.jsp”></jsp:forward>
- page内填写的是jsp的相对路径
- 注:在标签中间不可以添加任何字符,除了<jsp:param name=“00001” value=“beijing”/>,这相当于发送请求"/forward.jsp?00001=beijing"
- 在转发的页面中想要获取属性值,可以通过request.getParameter(“00001”)
- 示例
<%--原页面代码--%>
...
<jsp:forward page="forward.jsp">
<jsp:param name="00001" value="beijing"/>
<jsp:param name="00002" value="shanghai"/>
</jsp:forward>
<%--转发到的页面获取属性--%>
...
<%=request.getParameter("00001")%>
<%=request.getParameter("00002")%>
1.6 JSP九大内置对象
- jsp页面在转译成其对应的servlet文件的时候,会在service方法中自动声明一些对象,在jsp页面中可以直接使用
- 能在局部代码块和脚本调用中使用,但是不能在全局代码块中使用,因为全局代码块相当于定义在了service方法外,而service方法外部还没创建这九大对象
- 九大对象
- pageContext:表示页面的上下文对象,封存了其他的内置对象,封存了当前页面的运行信息。每一个页面都有一个对应的pageContext对象,伴随着当前页面的结束而结束
- request
- session
- application:ServletContext
- response
- page:代表当前jsp对象,跟java中的this类似
- exception:异常对象,存储当前运行的异常信息,必须在page指令中添加属性isErrorPage=“true”,service中才会创建该对象
- config:ServletConfig
- out:响应对象,jsp内部使用,带有缓存区的响应对象,比response高效
1.7 JSP四大作用域
- pageContext:当前页面
- request:请求
- session:一次会话
- application:项目内
<%--有了作用域,就可以在EL表达式中使用,效果与直接使用九大内置对象相同--%>
pageContext:<%=pageContext.getAttribute("key")%><br>
pageContext:${pageScope.key}<br>
1.8 JSP中路径问题
- 想要获得项目中的资源,可以使用相对路径,也可以使用绝对路径
- 相对路径:相对于当前页面的路径
- 资源的位置不可以随便更改
- 需要使用…/的方式进行文件夹跳出,如果目录比较深,操作起来麻烦
- 绝对路径:在请求的资源前面加/,表示当前服务器的根路径(http://localhost:8080/),使用的时候"/虚拟项目名/资源目录"
- 使用jsp自带的全局路径声明
- 相当于使用的相对路径不再是当前jsp路径,而是自定义的路径,一般改到"虚拟项目名"这层,使用时直接"资源目录",相当于改良了绝对路径表示法
- 示例
<%--
<%
//http :// 127.0.0.1 8080 /myfirstServlet
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";
%>
<html>
<head>
<base href="<%=basePath%>">
<title>Title</title>
</head>
<body>
<a href="wsh.jsp">tiaozhuan</a>
</body>
</html>
2 EL表达式
- 简化在jsp中获取作用域或请求数据的写法
2.1 传统方式的缺点
- 由于servlet与jsp二者不在同一个类中,jsp无法获取servlet中的泛型信息,因此必须进行强制转换
- 必须要导包
- 层次结构比较复杂
2.2 EL表达式
- Expression Language:一种表达式语言,语法简单
- 可以简化在jsp中获取作用域或请求数据的写法
- 替代getParameter(key)、getAttribute(key):${key}
- 不同作用域中,如果都通过addAttribute放入相同的key时,EL表达式取值顺序
- 以小的作用域的属性值为准
- 可以通过pageScope、requestScope、sessionScope、applicationScope获取指定作用域的数据,例:${requestScope.key}
- pageContext–>request–>session–>application
- 进行算数运算、关系运算、逻辑运算
- 如果是关系运算,返回true或false
- 此处"+"不能当做字符串连接符
- ${1+“abc”},执行时报错
- ${1+“2”},显式3
- 替代request.getHeader(key)
- ${header}:将请求头中信息封装为一个map对象并返回,注意setAttribute放入的属性值,无法通过该方法获取
- ${header[key]}或${header.host}:获取该map中,指定key的value值,如果一个host对应多个值报错
- ${headerValues[“accept-language”]}:获取一个数组,获得指定key值的一组value值,返回类型为String[]
- ${headerValues[“accept-language”][0]}:获得数组中的元素
- 替代request.getCookies
- ${cookie}:将cookie中信息封装为一个map对象并返回
- ${cookie.JSESSIONID}:获取该map中,指定key的value值,这个value是一个Cookie对象
- ${cookie.JSESSIONID.name}:获取该Cookie对象的name属性
- ${cookie.JSESSIONID.value}:获取该Cookie对象的value属性
2.3 EL表达式示例
- ELServlet
import entity.Address;
import entity.User;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
public class ElServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
String name = req.getParameter("name");
String pwd = req.getParameter("pwd");
System.out.println(name+":"+pwd);
req.setAttribute("a1","beijing");
User u = new User(1,"吴思含",new Address("辽宁省","沈阳市","皇姑区"));
User u2 = new User(2,"刘雪婷",new Address("辽宁省","大连市","普兰店"));
req.setAttribute("user",u);
ArrayList<User> list = new ArrayList<>();
list.add(u);
list.add(u2);
req.setAttribute("listwu",list);
HashMap<String,String> map = new HashMap<>();
map.put("china","beijing");
map.put("liaoning","shenyang");
req.setAttribute("mapwu",map);
HashMap<String,User> map2 = new HashMap<>();
map2.put("a1",u);
map2.put("a2",u2);
req.setAttribute("mapwu2",map2);
req.getRequestDispatcher("el.jsp").forward(req,resp);
}
}
- el.jsp
<%@ page import="entity.User" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.HashMap" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--1. 使用传统写法获取作用域中的值--%>
<%--注意getParameter获取值时,必须是头或体中的数据,而不是通过setAttribute放入的数据--%>
name:<%=request.getParameter("name")%>
pwd:<%=request.getParameter("pwd")%>
00001:<%=request.getAttribute("a1")%>
皇姑区:<%=((User)request.getAttribute("user")).getAddress().getTown()%>
普兰店:<%=(((User)((ArrayList)request.getAttribute("listwu")).get(1)).getAddress()).getTown()%>
beijing:<%=((HashMap)request.getAttribute("mapwu")).get("china")%>
皇姑区:<%=((User)((HashMap)request.getAttribute("mapwu2")).get("a1")).getAddress().getTown()%>
<br/>
<%--2. 使用EL表达式获取作用域中的值--%>
name:${name}
pwd:${pwd}
00001:${a1}
皇姑区:${user.address.town}
普兰店:${listwu[1].address.town}
beijing:${mapwu.china}
皇姑区:${mapwu2.a1.address.town}
<!--两者相同-->
皇姑区:${mapwu2["a1"].address.town}
<br>
<%
//必须先导入jsp—api.jar,否则编译无法通过
pageContext.setAttribute("key","pageContext");
request.setAttribute("key","request");
session.setAttribute("key","session");
application.setAttribute("key","application");
%>
key:${key}<br>
pageContext:${pageScope.key}<br>
request:${requestScope.key}<br>
session:${sessionScope.key}<br>
application:${applicationScope.key}<br>
${1+2}<br>
${1>2}<br>
<%--
执行时会报错
${1+"ab"}<br>
--%>
${1+"2"}<br>
${1+2}<br>
${1>2?"男":"女"}<br>
${true&&false}<br>
<!--一个包含所有头信息的map-->
${header}<br>
<!--两者用法相同-->
${header.host}<br>
${header["host"]}<br>
<!--当header中,有两个key值相同,value不同的属性时,可以用该方法,获取属性值的字符串数组,因此此处是一个String[]对象,打印[Ljava.lang.String; @ 6fba1c17-->
${headerValues["accept-language"]}<br>
<!--取String[]中的第一个元素,是String类型,因此打印zh-CN,zh; q = 0.9,zh-TW; q = 0.8,en-US; q = 0.7,en; q = 0.6-->
${headerValues["accept-language"][0]}<br>
<!--与${header["cookie"]}不同,header方式获取到的是cookie作为key的value的字符串,而后者,是包含所有cookie的map对象-->
${cookie}<br>
${cookie.JSESSIONID}<br>
${cookie.JSESSIONID.name}<br>
${cookie.JSESSIONID.value}<br>
</body>
</html>
3 JSTL
- Java server pages standarded tag library,即JSP标准标签库
- 帮助我们在jsp页面中添加复杂的逻辑判断,避免逻辑代码与页面标签混为一谈,即尽量不在jsp中编写java代码
- JSTL是EL的扩展,同时JSTL依赖于EL,可以方便的从作用域中获取值
- JSTL标签库导入
- 需下载jakarta-taglibs-standard-1.1.2.zip,将其内的jstl.jar、standard.jar放入WEB-INF/lib:因为标签实际上会被转为这两个jar包中的java类
- taglib导入标签库
- 有时标签库地址无法访问,可以人为设定标签库对应的tld文件:File-Settings-Schemas and DTDs
- uri:http://java.sun.com/jsp/jstl/core
- File:E:/sonar/jakarta-taglibs-standard-1.1.2/tld/c.tld
- 注意c.tld只是JSTL核心标签库的描述文件,此处相当于只能使用核心标签库
- 示例
<%@ 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>
</body>
</html>
3.1 JSTL内部分类
- 核心标签库:必须掌握
- 格式化标签库:掌握
- 函数标签库:了解
- XML标签库:了解
- SQL标签库:了解
3.2 JSTL中核心标签库中的标签
- out:输出标签
- value:要输出的值
- default:value为空时的默认值
- set:向作用域设置属性值
- var:表示参数的key
- value:参数的value
- scope:向哪个作用域设置属性值
- 注意:未配置scope时,默认向pageContext作用域中设置属性
- remove:删除作用域中的数据
- var:参数的key
- scope:指定作用域
- 注意:未配置scope时,默认删除所有作用域中数据
- if:
- test:填写逻辑判断表达式
- var:将条件表达式的结果,存储到新的变量
- scope:结果变量存储的作用域
- choose:
- 进行多重逻辑判断,类似于switch
- forEach
- begin:起始值
- end:结束值
- step:步长
- varStatus:表示循环状态的对象,其包含index、count等属性,表示当前循环的索引、值等
- var:集合、map中本次循环所对应的的那条数据。对于map,begin的值,表示map中的第几条数据,但要注意map无序,因此不会按一定顺序循环
- items:从作用域中获取的数据
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.HashMap" %>
<%@ 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>
<br>
<%request.setAttribute("att","value");%>
<c:out value="${att}" default="嘿嘿"></c:out><br>
<c:set var="java" value="page" scope="page" ></c:set>
<c:set var="java" value="request" scope="request" ></c:set>
<c:set var="java" value="session" scope="session" ></c:set>
<c:set var="java" value="application" scope="application" ></c:set>
<c:out value="${pageScope.java}"></c:out><br>
<c:out value="${requestScope.java}"></c:out><br>
<c:out value="${sessionScope.java}"></c:out><br>
<c:out value="${applicationScope.java}"></c:out><br>
<c:remove var="java" scope="request"></c:remove>
<c:out value="${pageScope.java}"></c:out><br>
<c:out value="${requestScope.java}"></c:out><br>
<c:out value="${sessionScope.java}"></c:out><br>
<c:out value="${applicationScope.java}"></c:out><br>
<c:set var="a" value="6" ></c:set>
<c:if test="${a>5}" var="flag" scope="request">
大于5岁
</c:if>
<c:set var="b" value="40" ></c:set>
<c:choose>
<c:when test="${b<10}">
少年<br>
</c:when>
<c:when test="${b<30}">
青年<br>
</c:when>
<c:when test="${b<50}">
中年<br>
</c:when>
<c:otherwise>
老年<br>
</c:otherwise>
</c:choose>
<table border="1px">
<tr>
<td>1</td>
<td>111</td>
</tr>
<tr>
<td>2</td>
<td>222</td>
</tr>
<tr>
<td>3</td>
<td>333</td>
</tr>
</table>
<c:forEach begin="0" end="5">
wusihan<br>
</c:forEach>
<c:forEach begin="0" end="3" step="2" varStatus="stats">
${stats.index}--${stats.count}--${stats.first}--${stats.last}<br>
</c:forEach>
<%
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("wusihan");
arrayList.add("liuxueting");
arrayList.add("wuzijin");
request.setAttribute("list",arrayList);
%>
<c:forEach begin="0" end="2" var="abc" items="${list}">
${abc}<br>
</c:forEach>
<%
HashMap<String,String> map = new HashMap<String,String>();
map.put("1","111");
map.put("2","222");
map.put("3","333");
request.setAttribute("map",map);
%>
<table border="1px">
<c:forEach begin="0" end="2" var="i" items="${map}">
<tr>
<td>${i.key}</td>
<td>${i.value}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
3.3 自学JSTL
- 菜鸟教程
https://www.runoob.com/jsp/jsp-jstl.html
- 需要时再看就可以