个人java学习路线-EL表达式和JSTL,文件的上传和下载
EL表达式介绍
EL:Expression Language 表达式语言
作用:代替jsp页面中表达式脚本在jsp页面中进行数据的输出(比jsp表达式脚本简洁)
EL和JSP对比
EL和JSP对比
<%
request.setAttribute("key","值");
%>
表达式脚本输出key的值:<%=request.getAttribute("key")%><br>
EL表达式输出key的值:${key}<br>
<%--表达式脚本输出不存在的key时输出null,EL输出空白--%>
表达式脚本输出key的值不存在:<%=request.getAttribute("key1")%><br>
EL表达式输出key的值不存在:${key1}<br>
EL表达式搜索域数据的顺序
EL表达式搜索域数据的顺序
pageContext,request,session,application
四个域中有相同的key时,按作用域从小到大顺序搜索
<%
pageContext.setAttribute("key","pageContext");
request.setAttribute("key","request");
session.setAttribute("key","session");
application.setAttribute("key","application");
%>
${key}<%--输出pageContext--%>
EL表达式输出Bean的普通属性,数组属性(List集合,map集合属性)
EL表达式输出Bean的普通属性,数组属性(List集合,map集合属性)
${person.age},不是直接输出person对象的age,而是找对应的get方法
<%
Person person=new Person();
person.setName("穷奇");
person.setAge(6452);
person.setPhones(new String[]{"18866663333","15577778888","16699998888"});
List<String> cities=new ArrayList<>();
cities.add("海内北经");
cities.add("西山经");
cities.add("西方");
person.setCities(cities);
Map<String,Object> map=new HashMap<>();
map.put("key1","少昊氏之子");
map.put("key2","毁信恶忠");
map.put("key3","崇饰恶言");
person.setMap(map);
pageContext.setAttribute("person",person);
%>
输出Person:${person}<br>
输出Person的name属性:${person.name}<br>
输出Person的phones数组属性:${person.phones[0]}<br><%--加下标,挨个输出--%>
输出Person的cities集合属性:${person.cities}<br><%--输出全部--%>
输出Person的cities集合中单个属性:${person.cities[0]}<br><%--单个加中括号下标--%>
输出Person的map集合属性:${person.map}<br><%--输出全部--%>
输出Person的map集合中某个key的值:${person.map.key1}<br><%--map后面加点key值--%>
输出Person的age属性:${person.age}<br>
ps:EL表达式这里person.age,不是直接输出,而是找对应的get方法(Boolean的是is方法),所以类中如果没有get方法,就无法输出。
EL表达式—运算
关系运算
== eq
!= ne
< it
> gt
<= le
>= ge
${12==12}或${12 eq 12}<br>
${12!=12}或${12 ne 12}<br>
${12<12}或${12 lt 12}<br>
${12>12}或${12 gt 12}<br>
${12<=12}或${12 le 12}<br>
${12>=12}或${12 ge 12}<br>
逻辑运算
&& and
|| or
! not
${12==1 && 12 >11}或${12==1 and 12 >11}<br>
${12==1 || 12 >11}或${12==1 or 12 >11}<br>
${! true}或${not true}<br>
算术运算
和java一样
其中:
18 / 12 可以写成 18 div 12
18 % 12 可以写成 18 mod 12
empty运算
empty运算可以判断一个数据是否为空,如果为空,则输出true,不为空输出false.
以下几种情况为空:
1>.值为null
2>.值为空字符串
3>.值时Object类型数组,长度为零的时候
4>.list集合,元素个数为零
5>.map集合,元素个数为零
<%
request.setAttribute("emptyNull",null);
request.setAttribute("emptyString","");
request.setAttribute("emptyArr",new Object[]{});
request.setAttribute("emptyList",new ArrayList<>());
request.setAttribute("emptyMap",new HashMap<String,Object>());
%>
1>.值为null<br>
${empty emptyNull}<br>
2>.值为空字符串<br>
${empty emptyString}<br>
3>.值时Object类型数组,长度为零的时候<br>
${empty emptyArr}<br>
4>.list集合,元素个数为零<br>
${empty emptyList}<br>
5>.map集合,元素个数为零<br>
${empty emptyMap}<br>
三元运算
和java一样
条件?语句1:语句2;
"."运算,和[]中括号运算符
点运算,可以输出Bean对象中某个属性的值
[]中括号运算,可以输出有序集合中某个元素的值
并且[]中括号运算,还可以输出map集合中key里含有特殊字符的key的值
例如:
map.put("a.a.a",aaaValue");
request.setAttribute("map",map);
用点运算显然无法访问:${map.a.a.a}
[]中括号运算可以访问:${map['a.a.a']}
EL表达式的11个隐含对象
EL表达式的11个隐含对象
变量 类型 作用
pageContext pageContextImpl 它可以获取jsp中的九大内置对象
pageScope Map<String,Object> 它可以获取pageContext域中的数据
requestScope Map<String,Object> 它可以获取request域中的数据
sessionScope Map<String,Object> 它可以获取session域中的数据
applicationScope Map<String,Object> 它可以获取ServletContext域中的数据
param Map<String,String> 它可以获取请求参数的值
paramValues Map<String,String[]> 它也可以获取请求参数的值,获取多个值的情况
header Map<String,String> 它可以获取请求头的信息
headerValues Map<String,String[]> 它也可以获取请求头的信息,获取多个值的情况
cookie Map<String,Cookie> 它可以获取当前请求的Cookie信息
initParam Map<String,String> 它可以获取在web.xml中配置的<context-param>上下文参数
EL获取四个特定域中的属性
pageScope ===== pageContext域
requestScope ===== request域
sessionScope ===== session域
applicationScope ===== ServletContext域
<%
pageContext.setAttribute("key1","pageContext1");
pageContext.setAttribute("key2","pageContext2");
request.setAttribute("key2","request");
session.setAttribute("key2","session");
application.setAttribute("key2","application");
%>
${key2}<br>
${requestScope.key2}<br>
页面输出:
pageContext2
request
pageContext对象的使用
常用的:
1>.协议
2>.服务器ip
3>.服务器端口
4>.获取工程路径
5>.获取请求方法
6>.获取客户端ip地址
7>.获取会话的id编号
其它方法
输出请求参数username的值:${param.username}<br>
输出请求参数password的值:${param.password}<br>
<hr>
输出请求参数username的第一个值: ${paramValues.username[0]}<br>
<hr>
输出请求头【User-Agent】的值:${header['User-Agent']}<br>
输出请求头【Connection】的值:${header.Connection}<br>
<hr>
输出请求头【User-Agent】数组的第一个值:${headerValues['User-Agent'][0]}<br>
<hr>
获取Cookie的名称: ${cookie.JSESSIONID.name}<br>
获取Cookie的值: ${cookie.JSESSIONID.value}<br>
<hr>
输出web.xml中<context-param>的名字:${initParam.username}<br>
输出web.xml中<context-param>的值:${initParam.url}<br>
JSTL标签库core核心库使用
JSTL 标签库 全称是指 JSP Standard Tag Library JSP 标准标签库。是一个不断完善的开放源代码的 JSP 标签库。
EL 表达式主要是为了替换 jsp 中的表达式脚本,而标签库则是为了替换代码脚本。这样使得整个 jsp 页面变得更佳简洁。
JSTL标签库使用
- 导入JSTL的jar包
- 引入jar包:(一般输入<c,idea就会自动引入了)
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
core核心库使用
1.<c:set/>
作用:往域中保存数据
<%--
1.<c:set/>
作用:往域中保存数据
域对象.setAttribute(key,value);
scope属性设置保存到哪个域
page表示PageContext域(默认值)
request表示Request域
session表示Session域
application表示ServletContext域
var属性设置key
value属性设置值
--%>
保存之前:${requestScope.abc}<br>
<c:set scope="request" var="abc" value="abcValue"/>
保存之后:${requestScope.abc}<br>
<hr>
网页输出:
保存之前:
保存之后:abcValue
2.<c:if/>
作用:做if判断
<%--
2.<c:if/>
作用:做if判断
test属性表示判断的条件(使用EL表达式输出)
--%>
<c:if test="${12==12}">
<h1>12等于12</h1><br>
</c:if>
<hr>
输出:12等于12
3.<c:choose><c:when><c:otherwise>标签
作用:多路判断,类似switch…case…default
<%--
<c:choose><c:when><c:otherwise>标签
作用:多路判断,类似switch..case...default
注意:
1.标签里不能用html注释,要使用jsp注释
2.when标签的父标签一定要是choose标签(嵌套注意)
<c:choose>
...
<c:otherwise>
<c:choose>
<c:when...>
</c:when>
<c:otherwise>
</c:otherwise>
</c:choose>
</c:otherwise>
</c:choose>
--%>
<%
request.setAttribute("height",178);
%>
<c:choose>
<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>
<h2>可还行</h2>
</c:otherwise>
</c:choose>
4.<c:forEach/>标签
作用:遍历
属性:
items 属性表示遍历的集合
var 属性表示遍历到的数据
begin 属性表示遍历的开始索引值,0开始
end 属性表示遍历的结束索引值
step 属性表示遍历的步长值,默认1
varStatus 属性表示遍历到的数据的状态
varStatus="status",后status的方法:
Object getCurrent(); 表示获取当前遍历到的数据
int getIndex(); 表示获取遍历的索引
int getCount(); 表示遍历的个数
boolean isFirst(); 表示当前遍历的数据是否是第一条
boolean isLast(); 表示当前遍历的数据是否是最后一条
Integer getBegin(); 获取begin属性值
Integer getEnd(); 获取end属性值
Integer getStep(); 获取step属性值
<%--
4.<c:forEach/>标签
作用:遍历
1.遍历1-10:
var属性表示循环的变量(也是当前正在遍历到的数据)
--%>
<c:forEach begin="1" end="10" var="i">
${i}
</c:forEach>
<br><hr>
<%--
2.遍历Object数组
--%>
<%
request.setAttribute("arr",new String[]{"18855554433","19988887777","15533336666"});
%>
<c:forEach items="${requestScope.arr}" var="item">
${item}
</c:forEach>
<hr>
<%
Map<String,Object> map=new HashMap<>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
request.setAttribute("map",map);
%>
<c:forEach items="${requestScope.map}" var="maptest">
${maptest.key}:${maptest.value}
</c:forEach>
<br><hr>
<%--
遍历List集合中的Student类
--%>
<%
List<Student> studentList=new ArrayList<>();
for (int i = 1; i <=10 ; i++) {
studentList.add(new Student(i,"username"+i,"password"+i,18+i,"phone"+i));
}
request.setAttribute("stus",studentList);
%>
<table border="1px">
<tr>
<th>编号</th>
<th>用户名</th>
<th>密码</th>
<th>年龄</th>
<th>电话</th>
<th>操作</th>
</tr>
<c:forEach begin="3" 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>删除 , 修改</td>
</tr>
</c:forEach>
</table>
<br><hr>
网页输出:
1 2 3 4 5 6 7 8 9 10
18855554433 19988887777 15533336666
key1:value1 key2:value2 key3:value3
编号 用户名 密码 年龄 电话 操作
4 username4 password4 22 phone4 删除 , 修改
6 username6 password6 24 phone6 删除 , 修改
8 username8 password8 26 phone8 删除 , 修改
文件的上传和下载
文件上传
步骤:
1.要有一个form标签,method=post请求
2.form标签的encType属性值必须为multipart/form-data值
3.在form标签中使用input type=file添加上传的文件
4.编写服务器代码(Servlet程序)接收,处理上传的数据
encType=multipart/form-data 表示提交的数据,以多段(每一个表单项一个数据段)的形式 进行拼接,然后以二进制流的形式发送给服务器
commons-fileupload.jar常用API介绍说明-文件上传
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.getString()
获取当前表单项的值
String FileItem.getName();
获取上传的文件名
void FileItem.getName(file);
将上传的文件写到 参数file所指向的硬盘位置
用例(Java代码):
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//先判断上传的数据是否是多段数据(只有是多数据,才是文件上传的)
if (ServletFileUpload.isMultipartContent(request)){
//创建FileItemFactory工厂实现类
FileItemFactory fileItemFactory=new DiskFileItemFactory();
//创建用于解析上传数据的工具类ServletFileUpload类
ServletFileUpload servletFileUpload=new ServletFileUpload(fileItemFactory);
try {
//解析上传数据,得到每一个表单项FileItem
List<FileItem> list=servletFileUpload.parseRequest(request);
//循环判断,每一个表单项,是普通类型,还是上传的文件
for (FileItem fileItem:list){
if (fileItem.isFormField()){
//普通表单项
System.out.println("表单项的name属性值:"+fileItem.getFieldName());
//参数UTF-8解决乱码问题
System.out.println("表单项的value属性值:"+fileItem.getString("UTF-8"));
}else{
System.out.println("表单项的name属性值:"+fileItem.getFieldName());
String name=new String(fileItem.getName().getBytes("GBK"),"UTF-8");
System.out.println("上传的文件名:"+name);
fileItem.write(new File("C:\\Users\\Lenovo\\Desktop\\"+name));//上传的位置,这里上传后会直接传到桌面
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
文件下载
步骤:
1.获取要下载的文件名
2.读取要下载的文件内容
3.把下载的文件内容回传给客户端
4.在回传前,通过响应头告诉客户端返回的数据类型
5.还要告诉客户端收到的数据是用于下载使用(还是使用响应头)
Java代码:
public class Download extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取要下载的文件名
String downloadFileName="a.png";
// 2.读取要下载的文件内容(通过ServletContext对象可以读取)
ServletContext servletContext=getServletContext();
// 3.把下载的文件内容回传给客户端
// 4.在回传前,通过响应头告诉客户端返回的数据类型
String mimeType=servletContext.getMimeType("/file/"+downloadFileName);
System.out.println("下载的文件类型:"+mimeType);
response.setContentType(mimeType);
// 5.还要告诉客户端收到的数据是用于下载使用(还是使用响应头)
//Content-Disposition响应头,表示收到的数据怎么处理
//attachment表示附件,表示下载使用
//filename=表示指定下载的文件名
//url编码是把汉字转换成为%xx%xx的格式(十六进制)
if (request.getHeader("User-Agent").contains("Firefox")){
//如果是火狐浏览器使用Base64编码
response.setHeader("Content-Disposition","attachment;filename==?UTF-8?B?"+ new BASE64Encoder().encode("希夫.jpg".getBytes("UTF-8"))+"?=");
}else {
//如果是IE或谷歌,使用URL编码操作
response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode("希夫.jpg","UTF-8"));
}
/*
/ 斜杠被服务器解析表示地址为http://ip:port/工程名/ 映射 到代码的Web目录
*/
InputStream resourceAsStream=servletContext.getResourceAsStream("/file/"+downloadFileName);
//获取响应的输出流
OutputStream outputStream=response.getOutputStream();
//读取输入流中的数据,复制给输出流,输出给客户端
IOUtils.copy(resourceAsStream,outputStream);
/*//火狐的编码
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);*/
}
}