厦工我的厦工😭😭😭😭😭😭😭😭,daisuki😍😍😍😍😍😍😍😍,寒假你别走😭😭😭😭😭😭😭😭
EL表达式
EL表达式的全称 : Expression Language 是表达式语言 EL表达式作用 ????: EL表达式主要是代替jsp页面中的表达式脚本在jsp页面中进行数据的输出
格式 : ${表达式}??????????(嗨呀怎么和Jquery这么像捏🤗)
1、EL表达式初入
1.1、EL表达式优势
因为EL表达式在输出数据的时候,要比jsp的表达式脚本要简洁很多😍😍,下面举例,输出页面中的数据
而且当输出不存在的值的时候,EL表达式不会出现null,下图,我们试试输出不存在的值
1.2、EL表达式搜索四个域数据的顺序
结论 : 生命周期短的域,先被搜索
证明 :
在前面的jsp,我们说过了四个域,分别是pageContext、request、session、application,其生命周期长短,从左到右,依次升高,那么如果,我这样写
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>这里是a.jsp</title>
</head>
<body>
<%
request.setAttribute("key","request");
session.setAttribute("key","session");
application.setAttribute("key","application");
pageContext.setAttribute("key","pageContext");
%>
${key}
</body>
</html>
这时从浏览器,取key,会是谁呢?🤔🤔🤔
是生命周期最短的pageContext捏😁,因此,我们这里证明了, 生命周期短的域,先被搜索
1.3、输出复杂的bean对象
先写个javaBean把,这里写个Person类
public class Person {
private String name;
private String[] phones;
private List<String> cities;
private Map<String,Object> map;
这时候我们写个EL表达式去取值
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>这是是c.jsp</title>
</head>
<body>
<%
Person person = new Person();
person.setName("哈哈哈");
person.setPhones(new String[]{"12345","123456","2233"});
List<String> cities = new ArrayList<String>();
cities.add("a市");
cities.add("b市");
cities.add("c市");
person.setCities(cities);
Map<String, Object> map = new HashMap<>();
map.put("k1","v1");
map.put("k2","v2");
map.put("k3","v3");
person.setMap(map);
pageContext.setAttribute("p",person);
%>
person的全部属性是 : ${p} <br>
person的name是: ${p.name} <br>
person的phone是: ${p.phones} <br>
person的phone[1]是: ${p.phones[1]} <br>
person的cities是: ${p.cities} <br>
person的cities[1]是: ${p.cities[1]} <br>
person的map是 : ${p.map} <br>
person的k1对应的值是 : ${p.map.k1} <br>
</body>
</html>
结论 : EL表达式根据get方法来获取bean的属性值
证明 :
这里我们在Person类中,只写了getAge()方法,并没有写age字段
用EL表达式获取
person的age是: ${p.age}
下图,我们发现,可以正常的获取
1.4、EL表达式—运算
EL表达式支持运算,并输出结果
关系运算
关系运算符 | 说明 | 范例 | 结果 |
---|
== 或 eq | 等于 | ${ 5 == 5} 或 ${ 5 eq 5} | true | != 或 ne | 不等于 | ${5!=5} 或${5ne5} | false | < 或 It | 小于 | ${3<5} 或 ${3lt5} | true | > 或 gt | 大于 | ${2>10} 或 ${2gt10} | false | <= 或 le | 小于等于 | ${5<=12} 或 ${5le 12} | true | >= 或 ge | 大于等于 | ${3>=5} 或 ${3ge5} | false |
逻辑运算
逻辑运算符 | 说明 | 范例 | 结果 |
---|
&& 或 and | 与运算符 | ${12==12 && 12<11 } 或 ${12 ==12 and 12 <11 } | false | || 或 or | 或运算 | ${12==12||12<11} 或 ${12==12or12<11} | true | ! 或 not | 取反运算 | ${!true} 或 ${not true} | false |
算数运算
算数运算符 | 说明 | 范例 | 结果 |
---|
+ | 加法 | ${12 + 18} | 30 | - | 减法 | ${18 - 8} | 10 | * | 乘法 | ${12 * 12} | 144 | / 或 div | 除法 | ${ 144 / 12} 或 ${144 div 12} | 12 | % 或 mod | 取模 | ${144 % 10} 或 ${144 mod 10} | 4 |
empty运算
empty运算可以判断一个数据是否为空,如果为空,则输出true,不为空输出false 。
以下几种情况为空: 1、值为null值的时候,为空 2、值为空串的时候,为空 3、值是Object类型数组,长度为零的时候 4、list集合,元素个数为零 5、map 集合,元素个数为零
🔬证明 :
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>这里是e.jsp</title>
</head>
<body>
<%
request.setAttribute("emptyNull",null);
request.setAttribute("emptyStr","");
request.setAttribute("emptyObject",new Object[]{});
ArrayList<Object> list = new ArrayList<>();
request.setAttribute("emptyList",list);
HashMap<Object, Object> map = new HashMap<>();
request.setAttribute("emptyMap",map);
%>
${empty emptyNull} <br>
${empty emptyStr} <br>
${empty emptyObject} <br>
${empty emptyList} <br>
${empty emptyMap} <br>
</body>
</html>
三元运算
表达式1? 表达式2 : 表达式3 如果表达式1的值为真,返回表达式2的值,如果表达式1的值为假,返回表达式3的值。
. 和 [ ]
点运算,可以输出Bean对象中某个属性的值。 []中括号运算,可以输出有序集合中某个元素的值。
并且[]中括号运算,还可以输出map集合中key里含有特殊字符的key的值。
map.put("a.a.a","aaa");
比如,如果我们这样取,会非常麻😨
$(map.a.a.a) 这样写是错误的
$(map['a.a.a']) 正确写法,' '或" "包起来
2、EL表达式11个隐藏对象
EL个达式中11个隐含对象,是EL表达式中自己定义的,可以直接使用
变量 | 类型 | 作用 |
---|
pageContext | PageContextlmpl | 它可以获取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 >上下文参数 |
2.1、获取四个域的属性
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>这里是f.jsp</title>
</head>
<body>
<%
pageContext.setAttribute("key","pageContext");
request.setAttribute("key","request");
session.setAttribute("key","session");
application.setAttribute("key","application");
%>
我们需要输出pageContext的key ${pageScope.key} <br>
我们需要输出request的key ${requestScope.key} <br>
我们需要输出session的key ${sessionScope.key} <br>
我们需要输出application的key ${applicationScope.key} <br>
</body>
</html>
2.2、pageContext
它可以获取jsp中的九大内置对象
常用来
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>这里用来测试pageContext</title>
</head>
<body>
1.协议: ${pageContext.request.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>
</html>
你甚至可以这写,来使代码方便
<%
pageContext.setAttribute("req",request);
%>
1.协议: ${req.scheme} <br>
2.3、剩下6个隐藏对象
param 和 paramValues
它可以获取请求参数的值
输出请求username ${param.username} <br>
输出请求password ${param.password} <br>
paramValues数组 ${paramValues} <br>
用paramValues输出请求username ${paramValues.username[0]} <br>
用paramValues输出请求password ${paramValues.password[0]} <br>
用paramValues输出hobby1 ${paramValues.hobby[0]} <br>
用paramValues输出hobby2 ${paramValues.hobby[1]} <br>
header 和 headerValues
它可以获取请求头的信息
header输出请求头【User-Agent】的值 ${header['User-Agent']}<br>
header输出请求头【Connection】的值 ${header['Connection']}<br>
headerValues输出请求头【User-Agent】的值 ${headerValues['User-Agent'][0]}<br>
cookie
它可以获取当前请求的Cookie信息
cookie ${cookie} <br>
cookie对象 ${cookie.JSESSIONID} <br>
cookie对象名称 ${cookie.JSESSIONID.name} <br>
cookie对象值 ${cookie.JSESSIONID.value} <br>
initParam
它可以获取在web.xml中配置的< context-param >上下文参数
先去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://localhost:3306</param-value>
</context-param>
JSTL
1、JSTL初入
1.1、JSTL介绍
JSTL标签库全称是指JSP Standard Tag Library ( JSP标准标签库),是一个不断完善的开放源代码的JSP标签库
EL表达式主要是为了替换jsp中的表达式脚本,而标签库则是为了替换代码脚本。这样使得整个jsp页面变得更佳简洁
1.2、JSTL的5个标签库
功能范围 | URI | 前缀 |
---|
核心标签库–重点 | http://java.sun.com/jsp/jst/core | c | 格式化 | http://java.sun.com/jsp/jst/fmt | fmt | 函数 | http://java.sun.com/jsp/jstl/functions | fn | 数据库(不使用) | http://java.sun.com/jsp/jst/sq1 | sql | XML(不使用) | http://java.sun.com/jsp/jstl/xml | x |
在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" %>
1.3、JSTL标签库使用步骤
1、先导入JSTL标签库的jar包
2、第二步,使用taglib指令引入标签库,🤤🤤🤤🤤,下面引入的是核心库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
2、Core核心库
2.1、<c:set>
作用 : set标签可以往域中保存数据
格式 :
<c:set scope=" " var =" " value=" " /></c:set>
scope属性 表示放到哪个域 page(PageContext域) 、request(Request域) 、session(Session域)、application(ServletContext域)
var属性 设置key是多少
value属性 设置值时多少
实践
保存之前: ${requestScope.abc} <br>
<c:set scope="request" var="abc" value="123"></c:set>
保存之后: ${requestScope.abc} <br>
2.2、<c:if>
作用 : 来做if判断
格式 :
<c:if text="">执行的内容</c:if>
text属性 表示判断的条件,里面写EL表达式
实践
<c:if test="${12 == 12}">
<h1>12等于12</h1>
</c:if>
<c:if test="${12 != 12}">
<h1>12不等于12</h1>
</c:if>
2.3、<c:choose><c:when><c:otherwise>
作用 : 多路判断。跟switch … case … default非常接近 而且不需要手动break😁
格式 :
<c:choose>
<c:when test=" ">
执行你想要的内容1
</c:when>
<c:when test=" ">
执行你想要的内容2
</c:when>
<c:otherwise>
执行你想要的内容3
</c:otherwise>
</c:choose>
chose标签 表示开始选择判断
when标签 表示每一种情况判断
otherwise标签 表示剩下的情况
实践
<c:choose>
<c:when test="${requestScope.age > 100}">
你真老
</c:when>
<c:when test="${requestScope.age < 100 && requestScope.age > 90}">
再活10年才算老
</c:when>
<c:otherwise>
你真年轻
</c:otherwise>
</c:choose>
注意点
1、标签里不能使用html注释,要使用jsp注释
2、when标签的父标签一定要是choose 标签
所以我们要在它的外面,加上一层choose
2.4、<c:forEach>
作用 : 遍历用的,不难看出🤔🤔
格式
<c:forEach begin="" end="" var=""></c:forEach>
begin属性 设置开始的索引 end属性 设置结束的索引 var属性 表示循环的变量(也是当前正在遍历到的数据)
<c:forEach begin="1" end="10" var="i"></c:forEach>
for(int i = 1 ; i <= 10 ; i++)
实践
遍历输出1~10
<table border="1">
<c:forEach begin="1" end="10" var="i">
<tr>
<td>第${i}行</td>
</tr>
</c:forEach>
</table>
3、<c:forEach>深入
3.1、遍历Object数组
格式 :
<c:forEach items="" var="" ></c:forEach>
items表示遍历的数据源(遍历的集合) var表示当前遍历到的数据
<c:forEach items="${requestScope.arr}" var="item">
for(Object item: arr)
实践
<%
request.setAttribute("arr",new String[]{"123","456","789"});
%>
<c:forEach items="${requestScope.arr}" var="item">
${item}
</c:forEach>
3.2、遍历Map集合
格式 :
<c:forEach items="" var="" ></c:forEach>
items表示遍历的数据源(遍历的集合) var表示当前遍历到的数据
java里,我们是这样遍历Map的
for(Map.Entry<String,Object> entry : map.entrySet()){
}
实践
<%
HashMap<String, Object> map = new HashMap<>();
map.put("k1","v1");
map.put("k2","v2");
map.put("k3","v3");
request.setAttribute("map",map);
%>
<c:forEach items="${requestScope.map}" var="entry">
输出entry: ${entry} <br>
输出entry的key: ${entry.key} <br>
输出entry的value: ${entry.value} <br>
</c:forEach>
3.3、遍历List集合
格式 :
<c:forEach items="" var="" ></c:forEach>
items表示遍历的数据源(遍历的集合) var表示当前遍历到的数据
遍历List集合,list中存放Student类,有属性:编号,用户名,密码,年龄
public class Student {
private Integer id;
private String username;
private String password;
private Integer age;
}
<%
ArrayList<Student> students = new ArrayList<>();
for(int i = 1 ; i <= 10 ; i++){
students.add(new Student(i,"student"+i,"pwd"+i,18+i))
}
request.setAttribute("students",students);
%>
<table border="1">
<tr>
<td>学号</td>
<td>用户名</td>
<td>密码</td>
<td>年龄</td>
<td>操作</td>
</tr>
<c:forEach items="${requestScope.students}" var="student">
<td>${student.id}</td>
<td>${student.username}</td>
<td>${student.password}</td>
<td>${student.age}</td>
<td>修改,删除</td>
</c:forEach>
</table>
3.4、forEarch所有属性详细介绍
<c:forEarch begin="" end="" step="" varStatus="" items="" var=""></c:forEarch>
items表示遍历的集合 var表示遍历到的数据 begin表示遍历的开始索引值 end表示结束的索引值
上面这些前面都有,那我们说说下面的😁😁😁
step属性
表示遍历的步长值
比如这里的,for(inti=1;i<10;i+=2),i+=2
varStatus属性表示当前遍历到的数据的状态
我们会发现varStatus是一个对象,还是一个内部类
然后我们再去找找他的位置在javax.servlet.jsp.jstl.core.LoopTagSupport找找看
发现他实现了LoopTagStatus类,那我们就去LoopTagStatus类康康把😍😍😍,下图是在LoopTagStatus接口的总结
实践
<%
ArrayList<Student> students = new ArrayList<>();
for(int i = 1 ; i <= 10 ; i++){
students.add(new Student(i,"student"+i,"pwd"+i,18+i));
}
request.setAttribute("students",students);
%>
<table border="1">
<tr>
<td>getCurrent()</td>
<td>getIndex()</td>
<td>getCount()</td>
<td>isFirst()</td>
<td>isLast()</td>
<td>getBegin()</td>
<td>getEnd()</td>
<td>getStep()</td>
</tr>
<c:forEach begin="3" end="8" step="2" varStatus="status" items="${requestScope.students}" var="student">
<tr>
<td>${status.current}</td>
<td>${status.index}</td>
<td>${status.count}</td>
<td>${status.first}</td>
<td>${status.last}</td>
<td>${status.begin}</td>
<td>${status.end}</td>
<td>${status.step}</td>
</tr>
</c:forEach>
</table>
文件的上传和下载
文件的_上传和下载,是非常常见的功能。很多的系统中,或者软件中都经常使用文件的上传和下载。 比如: QQ头像,就使用了.上传。 邮箱中也有附件的上传和下载功能。 OA系统中审批有附件材料的上传。
1、文件上传
1.1、文件上传初入
1、要有一个form标签,method=post 请求 2、form标签的encType属性值必须为multipart/form-data值 3、在form标签中使用input type=file添加上传的文件 4、编写服务器代码接收,处理上传的数据。
<form action="uploadServlet" method="post" enctype="multipart/form-data">
用户名: <input type="text" name="username"> <br/>
头像: <input type="file" name="photo">
<input type="submit" value="提交">
</form>
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("接收到上传的文件辣");
}
}
1.2、文件上传的http协议内容
服务器接收数据
因为浏览器给我的发送的是,二进制流,所以我们需要用二进制流来读取
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("接收到上传的文件辣");
ServletInputStream inputStream = request.getInputStream();
byte[] buffer = new byte[102400];
int read = inputStream.read(buffer);
System.out.println(new String(buffer,0,read));
}
下图为,二进制流读取到的内容
1.3、解析上传数据
我们用😍commons-fileupload.jar 里面的常用API 😍 来解析上传数据
第一步,就是需要导入两个jar包
commons-fileupload.jar需要依赖commons-io.jar 这个包,所以两个包我们都要引入。
commons-fileupload-1.2.1 .jar
commons-io-1.4.jar
常用API
我们主要是用ServletFileUpload这个类来解析数据
ServletFileUpload类: 用于解析上传数据
Fileltem类: 每一个表单项
方法 | 作用 |
---|
boolean ServletFileUpload.isMultipartContent(HttpServletRequest request) | 判断当前上传的数据格式是否是多段的格式 | public List<Fileltem> parseRequest(HttpServletRequest request) | 解析上传数据 | boolean FileItem. isFormField() | 判断当前这个表单项,是否是普通的表单项。还是上传的文件类型true为普通类型的表单项,false为上传的文件类型 | String FileItem.getF ieldName( ) | 获取表单项的name属性值 | String FileItem.getString() | 获取当前表单项的值 | String FileItem.getName() | 获取上传的文件名 | void FileItem.write( file ) | 将上传的文件写到参数file所指向抽硬盘位置 |
fileupload类库的使用
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if(ServletFileUpload.isMultipartContent(request)){
FileItemFactory fileItemFactory = new DiskFileItemFactory();
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
try {
List<FileItem> list = servletFileUpload.parseRequest(request);
for(FileItem fileItem : list){
if(fileItem.isFormField()){
System.out.println("表单项的name属性值: " + fileItem.getFieldName());
System.out.println("表单项的value属性值: " + fileItem.getString("UTF-8"));
}else{
System.out.println("表单项的name属性值" + fileItem.getFieldName());
System.out.println("上传的文件名" + fileItem.getName());
fileItem.write(new File("d\\" + fileItem.getName()));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
2、文件下载
2.1、实现文件下载
图解
代码实现
public class DownLoadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String downLoadFileName = "p.jpg";
ServletContext servletContext = getServletContext();
String mimeType = servletContext.getMimeType("/file/" + downLoadFileName);
System.out.println("下载的文件类型为: " + mimeType);
response.setContentType(mimeType);
response.setHeader("Content-Disposition","attachment;filename=" + downLoadFileName);
InputStream resourceAsStream = servletContext.getResourceAsStream("/file/" + downLoadFileName);
ServletOutputStream outputStream = response.getOutputStream();
IOUtils.copy(resourceAsStream,outputStream);
}
}
2.2、中文乱码问题
谷歌浏览器和IE浏览器,我们可以用URLEncoder,解决下载的文件名是中文乱码的问题
response.setHeader("Content-Disposition","attachment;filename=中文.jpg");
我们这么改之后,会出现下图的问题,我们去看看响应头,就会发现http协议不支持中文
下面我们这么修改,url编码是把汉字转为%xx%xx的格式
response.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode("中文.jpg","UTF-8"));
确实是中文,没有问题了,而且url编码确实是把汉字转为%xx%xx的格式
2.3、base64编码解决中文乱码
base64编码,可以解决火狐浏览器的附加中文名词问题
编码
public class Base64Test {
public static void main(String[] args) throws UnsupportedEncodingException {
String context = "这是需要Base64编码的内容";
BASE64Encoder base64Encoder = new BASE64Encoder();
String encodeString = base64Encoder.encode(context.getBytes("UTF-8"));
System.out.println(encodeString);
}
}
解码
这里,我们对上面得到的6L+Z5piv6ZyA6KaBQmFzZTY057yW56CB55qE5YaF5a65进行解码
public class Base64Test {
public static void main(String[] args) throws Exception {
BASE64Decoder base64Decoder = new BASE64Decoder();
byte[] buffer = base64Decoder.decodeBuffer("6L+Z5piv6ZyA6KaBQmFzZTY057yW56CB55qE5YaF5a65");
String context = new String(buffer,"UTF-8");
System.out.println(context);
}
}
解决火狐浏览器问题
如果客户端浏览器是火狐浏览器。那么我们需 要对中文名进行BASE64的编码操作 这时候需要把请求头Content-Disposition: attachment;filename=中文名 编码成为: Content -Disposition:attachment; filename== ?charset?B?xxxxx?=
?
=?charset?B?xxxx?= | 说明 |
---|
=? | 表示编码内容的开始 | charset | 表示字符集 | B | 表示BASE64编码 | XXXX | 表示文件名BASE64编码后的内容 | ?= | 表示编码内容的结束 |
response.setHeader("Content-Disposition","attachment;filename==?UTF-8?B?"+new BASE64Encoder().encode("中文.jpg".getBytes("UTF-8")) +"?=" );
假装这是火狐浏览器(🐕
解决IE浏览器乱码问题
现在发现IE浏览器又出现乱码了,如下图,那么我们就结合刚刚所学内容,使用分支语句,来解决
if(request.getHeader("User-Agent").contains("Chrome")){
response.setHeader("Content-Disposition", "attachment;filename==?UTF-8?B?" + new BASE64Encoder().encode("中文.jpg".getBytes("UTF-8")) + "?=");
} else{
response.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode("中文.jpg","UTF-8"));
}
距离寒假结束还有9day
|