目录
EL表达式
<body>
<%
request.setAttribute("key","值");
%>
表达式脚本输出 key 的值是:
<%=request.getAttribute("key1")==null?"":request.getAttribute("key1")%><br/>//实现输出null和EL一样的效果
EL表达式输出key的值是:${key1}
</body>
EL表达式搜索域数据的顺序
<body>
<%
//往四个域中都保存了相同的 key 的数据。
request.setAttribute("key", "request");
session.setAttribute("key", "session");
application.setAttribute("key", "application");
pageContext.setAttribute("key", "pageContext");
%>
${key}
</body>
EL表达式输出Bean的普通属性,数组属性,List集合属性,map集合属性
public class Person {
// i.需求——输出 Person 类中普通属性,数组属性。list 集合属性和 map 集合属性。
private String name;
private String[] phones;
private List cities;
private Map<String,Object> map;
public int getAge() {
return 18;
}
... ...
}
输出的代码:
<body>
<%
Person person = new Person();
person.setName("国哥好帅!");
person.setPhones(new String[]{"18610541354","18688886666","18699998888"});
List cities = new ArrayList();
cities.add("北京");
cities.add("上海");
cities.add("深圳");
person.setCities(cities);
Map<String,Object>map = new HashMap<>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
person.setMap(map);
pageContext.setAttribute("p", person);
%>
输出Person:${ p }<br/>
输出Person的name属性:${p.name} <br>//p表示Person对象
输出Person的pnones数组属性值:${p.phones[2]} <br>
输出Person的cities集合中的元素值:${p.cities} <br>
输出Person的List集合中个别元素值:${p.cities[2]} <br>
输出Person的Map集合: ${p.map} <br>
输出Person的Map集合中某个 key 的值: ${p.map.key3} <br>
输出Person的age属性:${p.age} <br>18//EL表达式中找的不是属性,而是属性对应的方法get方法(读方法)
body>
EL表达式中找的不是属性,而是属性对应的方法get方法(读方法)
3)算数运算
<body>
<%
// 1、值为 null 值的时候,为空
request.setAttribute("emptyNull", null);
// 2、值为空串的时候,为空
request.setAttribute("emptyStr", "");
// 3、值是 Object 类型数组,长度为零的时候
request.setAttribute("emptyArr", new Object[]{});
// 4、list 集合,元素个数为零
List list = new ArrayList<>();
// list.add("abc");
request.setAttribute("emptyList", list);
// 5、map 集合,元素个数为零
Map map = new HashMap();
// map.put("key1", "value1");
request.setAttribute("emptyMap", map);
%>
${ empty emptyNull } <br/>
${ empty emptyStr } <br/>
${ empty emptyArr } <br/>
${ empty emptyList } <br/>
${ empty emptyMap } <br/>
body>
<body>
<%
Map map = new HashMap();
map.put("a.a.a", "aaaValue");
map.put("b+b+b", "bbbValue");
map.put("c-c-c", "cccValue");
request.setAttribute("map", map);
%>
%{map.a.a.a}//无法运算
${ map['a.a.a'] } <br>
${ map["b+b+b"] } <br>
${ map['c-c-c'] } <br>
</body>
<body>
<%
pageContext.setAttribute("key1", "pageContext1");
pageContext.setAttribute("key2", "pageContext2");
request.setAttribute("key2", "request");
session.setAttribute("key2", "session");
application.setAttribute("key2", "application");
%>
${ applicationScope.key2 }//输出map中某个值
</body>
pageContext对象的使用
通过request对象
<body>
<%--
request.getScheme() 它可以获取请求的协议
request.getServerName() 获取请求的服务器ip或域名
request.getServerPort() 获取请求的服务器端口号
request.getContextPath() 获取当前工程路径
request.getMethod() 获取请求的方式(GET或POST)
request.getRemoteHost() 获取客户端的ip地址
session.getId() 获取会话的唯一标识
--%>
<%
pageContext.setAttribute("req", request);
%>
不使用EL的写法
<%=request.getScheme() %> <br>
使用EL后的写法
1.协议: ${ req.scheme }<br>
2.服务器 ip:${ pageContext.request.serverName }<br>
3.服务器端口:${ pageContext.request.serverPort }<br>
4.获取工程路径:${ pageContext.request.contextPath }<br>
5.获取请求方法:${ pageContext.request.method }<br>
6.获取客户端 ip 地址:${ pageContext.request.remoteHost }<br>
7.获取会话的 id 编号:${ pageContext.session.id }<br>
</body>
EL表达式其他隐含对象的使用
输出请求参数 username 的值:${ param.username } <br>
输出请求参数 password 的值:${ param.password } <br>
输出请求参数 username 的值:${ paramValues.username[0] } <br>
输出请求参数 hobby 的值:${ paramValues.hobby[0] } <br>
输出请求参数 hobby 的值:${ paramValues.hobby[1] } <br>
输出请求头【User-Agent】的值:${ header['User-Agent'] } <br>//有-的特殊值
输出请求头【Connection】的值:${ header.Connection } <br>
输出请求头【User-Agent】的值:${ headerValues['User-Agent'][0] } <br>
获取Cookie的名称:${ cookie.JSESSIONID.name } <br>
获取Cookie的值:${ cookie.JSESSIONID.value } <br>
web.xml 中的配置:
<context-param>
<param-name>username</param-name>
<param-value>root</param-value>
</context-param>
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql:///test</param-value>
</context-param>
输出<Context-param>username 的值:${ initParam.username } <br>
输出<Context-param>url 的值:${ initParam.url } <br>
JSTL标签库(次重点)
在jsp标签库中使用taglib指令引入标签库
CORE 标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
XML 标签库
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
FMT 标签库
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
SQL 标签库
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
FUNCTIONS 标签库
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
作用:set标签可以往域中保存数据
<%--
i.<c:set />
作用:set 标签可以往域中保存数据
域对象.setAttribute(key,value);
scope 属性设置保存到哪个域
page 表示 PageContext 域(默认值)
request 表示 Request 域
session 表示 Session 域
application 表示 ServletContext 域
var 属性设置 key 是多少
value 属性设置值
--%>
保存之前:${ sessionScope.abc } <br> 无数据
<c:set scope="session" var="abc" value="abcValue"/>
保存之后:${ sessionScope.abc } <br> abcValue
<c:if/>
if标签用来做if判断。
<%--
ii.<c:if />
if 标签用来做 if 判断。
test 属性表示判断的条件(使用 EL 表达式输出)
--%>
<c:if test="${ 12 == 12 }">
<h1>12 等于 12</h1>
</c:if>
<c:if test="${ 12 != 12 }">
<h1>12 不等于 12</h1>
</c:if>
<%--
<c:choose> <c:when> <c:otherwise>标签
作用:多路判断。跟 switch ... case .... default 非常接近
choose 标签开始选择判断
when 标签表示每一种判断情况
test 属性表示当前这种判断情况的值
otherwise 标签表示剩下的情况
<c:choose> <c:when> <c:otherwise>标签使用时需要注意的点:
1、标签里不能使用 html 注释,要使用 jsp 注释
2、when 标签的父标签一定要是 choose 标签
--%>
<%
request.setAttribute("height", 180);
%>
<c:choose>
<%-- 这是 html 注释 --%>//会报错
<c:when test="${ requestScope.height > 190 }">
<h2>小巨人</h2>
</c:when>
<c:when test="${ requestScope.height > 180 }">
<h2>很高</h2>
</c:when>
<c:when test="${ requestScope.height > 170 }">
<h2>还可以</h2>
</c:when>
<c:otherwise>
<c:choose>
<c:when test="${requestScope.height > 160}">
<h3>大于 160</h3>
</c:when>
<c:when test="${requestScope.height > 150}">
<h3>大于 150</h3>
</c:when>
<c:when test="${requestScope.height > 140}">
<h3>大于 140</h3>
</c:when>
<c:otherwise>
其他小于 140
</c:otherwise>
</c:choose>
</c:otherwise>
</c:choose>
<%--1.遍历 1 到 10,输出
begin 属性设置开始的索引
end 属性设置结束的索引
var 属性表示循环的变量(也是当前正在遍历到的数据)
for (int i = 1; i < 10; i++)
--%>
<table border="1">
<c:forEach begin="1" end="10" var="i">
<tr>
<td>第${i}行</td>
</tr>
</c:forEach>
</table>
遍历Object数组
<%-- 2.遍历 Object 数组
for (Object item: arr)
items 表示遍历的数据源(遍历的集合)
var 表示当前遍历到的数据
--%>
<%
request.setAttribute("arr", new String[]{"18610541354","18688886666","18699998888"});
%>
<c:forEach items="${ requestScope.arr }" var="item">
${ item } <br>
</c:forEach>
遍历Map集合
示例代码:
<%
Map<String,Object> map = new HashMap<String, Object>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
// for ( Map.Entry<String,Object> entry : map.entrySet()) {
// }
request.setAttribute("map", map);
%>
<c:forEach items="${ requestScope.map }" var="entry">//entry表示每一组键值对
<h1>${entry.key} = ${entry.value}</h1>
</c:forEach>
遍历List集合---list中存放 Student类,有属性:编号,用户名,密码,年龄,电话信息
public class Student {
//4.编号,用户名,密码,年龄,电话信息
private Integer id;
private String username;
private String password;
private Integer age;
private String phone;
......
}
<%--4.遍历 List 集合---list 中存放 Student 类,有属性:编号,用户名,密码,年龄,电话信息--%>
<%
List<Student> studentList = new ArrayList<Student>();
for (int i = 1; i <= 10; i++) {
studentList.add(new Student(i,"username"+i ,"pass"+i,18+i,"phone"+i));
}
request.setAttribute("stus", studentList);
%>
<table>
<tr>
<th>编号</th>
<th>用户名</th>
<th>密码</th>
<th>年龄</th>
<th>电话</th>
<th>操作</th>
</tr>
<%--
items 表示遍历的集合
var 表示遍历到的数据
begin 表示遍历的开始索引值
end 表示结束的索引值,索引值是从0开始的
step 属性表示遍历的步长值
varStatus 属性表示当前遍历到的数据的状态
for(int i = 1; i < 10; i+=2)
--%>
<c:forEach begin="2" end="7" step="2" varStatus="status" items="${requestScope.stus}" var="stu">
<tr>
<td>${stu.id}</td>
<td>${stu.username}</td>
<td>${stu.password}</td>
<td>${stu.age}</td>
<td>${stu.phone}</td>
<td>${status.step}</td>
</tr>
</c:forEach>
</table>
文件的上传和下载
文件的上传
1、要有一个form标签,method=post请求
2、form标签的encType属性值必须为multipart/form-data值
3、在form标签中使用input type=file添加上传的文件
4、编写服务器代码(Servlet程序)接收,处理上传的数据。
<form action="http://localhost:8080/el_jstl/upload" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username"/><br/>
头像:<input type="file" name="phone"><br>
<input type="submit" value="上传">
</form>
文件上传时发送的HTTP协议的内容说明
get请求有长度限制,所以用post
encType=multipart/form-data 表示提交的数据,以多段(每一个表单项一个数据段)的形式进行拼接,然后以二进制流的形式发送给服务器。使用第三方jar对上传数据进行解析。
commons-fileupload.jar常用API介绍说明
commons-fileupload.jar需要依赖 commons-io.jar这个包,所以两个包我们都要引入。
第一步,就是需要导入两个jar包:
commons-fileupload-1.2.1.jar
commons-io-1.4.jar
commons-fileupload.jar 和 commons-io.jar 包中,我们常用的类有哪些?
ServletFileUpload类,用于解析上传的数据。
FileItem类,表示每一个表单项。
boolean ServletFileUpload.isMultipartContent(HttpServletRequest request);判断当前上传的数据格式是否是多段的格式。
public List<FileItem> parseRequest(HttpServletRequest request)解析上传的数据
boolean FileItem.isFormField()判断当前这个表单项,是否是普通的表单项。还是上传的文件类型。
true 表示普通类型的表单项false 表示上传的文件类型
String FileItem.getFieldName()获取表单项的name属性值
String FileItem.getString()获取当前表单项的值。
String FileItem.getName();获取上传的文件名
void FileItem.write( file );将上传的文件写到 参数 file 所指向抽硬盘位置
fileupload类库的使用
上传文件的表单upload.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/el_jstl/upload" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username"><br/>
头像:<input type="file" name="photo"><br/>
<input type="submit" value="上传">
</form>
</body>
</html>
解析上传的数据代码:
public class UploadServletServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.先判断上传的数据是否是多段数据(只有是多段的数据才是文件上传的)
if(ServletFileUpload.isMultipartContent(request)){
//创建FileItemFactory工厂实现类
FileItemFactory fileItemFactory = new DiskFileItemFactory();
//创建用于解析上传数据的工具类ServletFileUpload类对象
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
try {
List<FileItem> list = servletFileUpload.parseRequest(request);
for(FileItem fileItem:list){
if(fileItem.isFormField()){
//普通表单项
System.out.println("表单项的属性名是"+fileItem.getFieldName());
//餐宿utf-8,解决乱码问题
System.out.println("表单项的value值是"+fileItem.getString("UTF-8"));
}else{
//文件表单
//普通表单项
System.out.println("表单项的属性名是"+fileItem.getFieldName());
System.out.println("上传的文件名"+fileItem.getName());
fileItem.write(new File("D:\\"+fileItem.getName()));
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
文件下载
下载的常用API说明:
response.getOutputStream();
servletContext.getResourceAsStream();
servletContext.getMimeType();//数据类型的字符串描述符
response.setContentType();
response.setHeader("Content-Disposition", "attachment; fileName=1.jpg");
这个响应头告诉浏览器。这是需要下载的。而attachment表示附件,也就是下载的一个文件。fileName=后面,表示下载的文件名。
public class DownloadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1获取要下载的文件名
String downloadFileName = "avatar.jpg";
//2.获取要下载的文件内容(通过servletContext对象可以读取)
ServletContext servletContext = getServletContext();
InputStream resourceAsStream = servletContext.getResourceAsStream("/file/" + downloadFileName);
//获取要下载文件的类型
String mimeType = servletContext.getMimeType("/file/" + downloadFileName);
System.out.println("下载的文件类型"+mimeType);
//4.在回传前,通过响应头告诉客户端返回的数据类型
response.setContentType(mimeType);
//5.通过响应头告诉客户端收到的数据是否用于下载使用
//Content-Disposition响应头表示收到的数据怎么处理
response.setHeader("Content-Disposition", "attachment; fileName="+downloadFileName);
//获取响应的输出流
ServletOutputStream outputStream = response.getOutputStream();
//3.使用jar包中的方法,读取输入流的内容复制给输出流,输出给客户端
IOUtils.copy(resourceAsStream,outputStream);
}
}
完成上面的两个步骤,下载文件是没问题了。但是如果我们要下载的文件是中文名的话。你会发现,下载无法正确显示出正确的中文名。原因是在响应头中,不能包含有中文字符,只能包含 ASCII 码。
// 把中文名进行 UTF-8 编码操作。
String str = "attachment; fileName=" + URLEncoder.encode("中文.jpg", "UTF-8");
// 然后把编码后的字符串设置到响应头中
response.setHeader("Content-Disposition", str);
public class Base64Test {
public static void main(String[] args) throws Exception {
String content = "这是需要Base64编码的内容";
// 创建一个Base64编码器
BASE64Encoder base64Encoder = new BASE64Encoder();
// 执行Base64编码操作
String encodedString = base64Encoder.encode(content.getBytes("UTF-8"));
System.out.println( encodedString );
// 创建Base64解码器
BASE64Decoder base64Decoder = new BASE64Decoder();
// 解码操作
byte[] bytes = base64Decoder.decodeBuffer(encodedString);
String str = new String(bytes, "UTF-8");
System.out.println(str);
}
}
=? 表示编码内容的开始
charset 表示字符集
B 表示BASE64编码
xxxx 表示文件名BASE64编码后的内容
?= 表示编码内容的结束
// 使用下面的格式进行 BASE64 编码后
String str = "attachment; fileName=" + "=?utf-8?B?"
+ new BASE64Encoder().encode("中文.jpg".getBytes("utf-8")) + "?=";
// 设置到响应头中
response.setHeader("Content-Disposition", str);
那么我们如何解决上面两种不同编解码方式呢。我们只需要通过判断请求头中User-Agent这个请求头携带过来的浏览器信息即可判断出是什么浏览器。
String ua = request.getHeader("User-Agent");
// 判断是否是火狐浏览器
if (ua.contains("Firefox")) {
// 使用下面的格式进行 BASE64 编码后
String str = "attachment; fileName=" + "=?utf-8?B?"
+ new BASE64Encoder().encode("中文.jpg".getBytes("utf-8")) + "?=";
// 设置到响应头中response.setHeader("Content-Disposition", str);
} else {
// 把中文名进行 UTF-8 编码操作。
String str = "attachment; fileName=" + URLEncoder.encode("中文.jpg", "UTF-8");
// 然后把编码后的字符串设置到响应头中
response.setHeader("Content-Disposition", str);
}
public class Download extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1、获取要下载的文件名
String downloadFileName = "2.jpg";
// 2、读取要下载的文件内容 (通过ServletContext对象可以读取)
ServletContext servletContext = getServletContext();
// 获取要下载的文件类型
String mimeType = servletContext.getMimeType("/file/" + downloadFileName);
System.out.println("下载的文件类型:" + mimeType);
// 4、在回传前,通过响应头告诉客户端返回的数据类型
resp.setContentType(mimeType);
// 5、还要告诉客户端收到的数据是用于下载使用(还是使用响应头)
// Content-Disposition响应头,表示收到的数据怎么处理
// attachment表示附件,表示下载使用
// filename= 表示指定下载的文件名
// url编码是把汉字转换成为%xx%xx的格式
if (req.getHeader("User-Agent").contains("Firefox")) {
// 如果是火狐浏览器使用Base64编码
resp.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?" + new BASE64Encoder().encode("中国.jpg".getBytes("UTF-8")) + "?=");
} else {
// 如果不是火狐,是IE或谷歌,使用URL编码操作
resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("中国.jpg", "UTF-8"));
}
/**
* /斜杠被服务器解析表示地址为http://ip:prot/工程名/ 映射 到代码的Web目录
*/
InputStream resourceAsStream = servletContext.getResourceAsStream("/file/" + downloadFileName);
// 获取响应的输出流
OutputStream outputStream = resp.getOutputStream();
// 3、把下载的文件内容回传给客户端
// 读取输入流中全部的数据,复制给输出流,输出给客户端
IOUtils.copy(resourceAsStream, outputStream);
}
}