JavaWeb 学习笔记总结( 二 )

1. EL表达式


El表达式的全称:Expression Language(表达式语言)。

EL表达式的作用:主要替代jsp页面中的表达式脚本在jsp页面进行数据的输出。


为什么要要用EL表达式来替代jsp的数据输出?

因为EL表达式在输出数据的时候,要比jsp的表达式脚本要简洁很多。


举例:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Express Language</title>
</head>
<body>
    <%
        request.setAttribute("key","值");
    %>

    表达式脚本输出key的值是:<%=request.getAttribute("key")%><br>
    表达式脚本输出不存在的key2的值是:<%=request.getAttribute("key2")%><br>
    <hr>
    EL表达式输出key的值是:${key}<br>
    EL表达式输出不能存的key2的值是:${key2}
</body>
</html>

上面的输出结果是不同的!
在这里插入图片描述
如果想要表达式也是空串,还得写成三元表达式来判断:

<%=request.getAttribute("key2")==null?"":request.getAttribute("key2")%><br>

相比较EL表达式更为简洁。


总结:

  • El表达式的格式是:${表达式} 。
  • EL表达式在输出null值时,输出的是空串‘;而jsp表达式脚本输出null值时,输出null字符串。

2. EL 表达式 搜索域数据的顺序


EL表达式主要在jsp页面中输出数据,而且主要输出域对象中的数据。

那么,如果四个域中都有相同的key的数据时,就是有重复的key值。

EL表达式会按照四个域的从小到大的顺序,查找,查找到就输出。

pageContext < request < session < application

<%@ 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>
	<% 
		//四个域中都保存了相同的数据
		application.setAttribute("key", "application");
		session.setAttribute("key", "session");//session保存的数据,必须关闭浏览器后才消失
		request.setAttribute("key", "request");
		pageContext.setAttribute("key", "pageContent");
		
		//当四个域中都有相同的key的数据时,EL表达式会按照四个域的从小到大的顺序,查找,查找到就输出。
		//pageContext < request < session < application
	%>
	
	${key}
</body>
</html>

3. El表达式 调用类属性


我们在写EL表达式时,调用属性时,并不是直接调用属性,而是先调用属性对应的get方法,因此,如果我们想要把类中的属性使用EL表达式展现在jsp页面上,我们必须在java类中定义属性对应的get方法!

案例:
person.java 代码:

package com.test.el01;

import java.util.List;
import java.util.Map;

public class Person {
	
	private String name;
	private String[] phones;
	private List<String> cities;
	private Map<String,Object> map;
	private int age = 10;
	
	//倘若没有age的get方法,那么EL表达式调用age会直接报错!
	//public int getAge() {
	//	return age;
	//}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String[] getPhones() {
		return phones;
	}
	public void setPhones(String[] phones) {
		this.phones = phones;
	}
	public List<String> getCities() {
		return cities;
	}
	public void setCities(List<String> cities) {
		this.cities = cities;
	}
	public Map<String, Object> getMap() {
		return map;
	}
	public void setMap(Map<String, Object> map) {
		this.map = map;
	}
	
	public Person() {
		super();
	}
	
	public Person(String name, String[] phones, List<String> cities, Map<String, Object> map) {
		super();
		this.name = name;
		this.phones = phones;
		this.cities = cities;
		this.map = map;
	}
	
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "name:"+name+","+"phones:"+phones+","+"cities:"+cities+","+"map:"+map;
	}
	
}

jsp页面:

<%@page import="java.util.Map"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="com.test.el01.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<% 
		Person p = new Person();
		p.setName("张三");
		p.setPhones(new String[]{"1234567","12212331"});
		
		List<String> cities = new ArrayList<String>();
		cities.add("北京");
		cities.add("上海");
		p.setCities(cities);
		
		Map<String,Object> map = new HashMap<String,Object>();
		map.put("key1", "value1");
		map.put("key2", "value2");
		map.put("key3", "value3");
		p.setMap(map);
		
		pageContext.setAttribute("person", p);
	%>
	
	输出Person:${person}<br>
	输出Person的name属性:${person.name}<br>
	输出Person的phones数组的属性值:${person.phones[0]}<br> 
	输出Person的cities集合的属性值组:${person.cities}<br> 
	输出Person的cities集合的属性的某一个值:(和数组差不多。)${person.cities[1]}<br> 
	输出Person的map集合的属性:${person.map}<br> 
	输出Person的map集合的属性的某一个key值:${person.map.key2}<br> 
	输出Person的age属性值:${person.age}<br> 
	
</body>
</html>

在这里插入图片描述

4. EL表达式 运算

4.1 关系运算符


在这里插入图片描述

4.2 逻辑运算符


在这里插入图片描述

4.3 算数运算符


在这里插入图片描述

5. EL表达式 empty运算


empty运算可以判断一个数据是否为空,如果为空,则输出true,不为空输出false。

什么情况下EL表达式为空?

  • 值为null值得时候,为空。
  • 值为空串的时候,为空。
  • 值是Object类型数组,长度为零的时候。
  • list集合,元素个数为零。
  • map集合,元素个数为零。
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.ArrayList"%>
<%@ 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>
	<% 
		//1.值为null值得时候,为空。
		request.setAttribute("emptyNull", null);
		//2.值为空串的时候,为空。
		request.setAttribute("emptyStr", "");
		//3.值是Object类型数组,长度为零的时候。
		request.setAttribute("emptyArr", new Object[]{});
		//4.list集合,元素个数为零。
		request.setAttribute("emptyList", new ArrayList());
		//5.map集合,元素个数为零。
		request.setAttribute("emptyMap", new HashMap());
	%>
	
	${ empty emptyNull }<br>
	${ empty emptyStr }<br>
	${ empty emptyArr }<br>
	${ empty emptyList }<br>
	${ empty emptyMap }<br>
	
</body>
</html>

在这里插入图片描述

6. EL表达式 三元运算 , .点运算符,[]中括号运算符


EL中三元表达式如下:

${ 表达式1?表达式2:表达式3 }

例如:${ 12>3 ? “胡说3大于12”:true}


.点运算,可以输出类对象中某个属性的值,就是负责调用的。

[]中括号运算,可以输出有序集合中某个元素的值。

并且[]中括号运算,还可以输出map集合中key里含有特殊字符的key的值,就像下面的案例一样,本质上就是区分一些特殊字符的情况。

<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.ArrayList"%>
<%@ 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>
	<% 
		Map<String,Object> map = new HashMap<String,Object>();
		map.put("a.a.a", "value1");
		map.put("b+b+b", "value2");
		map.put("c-c-c", "value3");
		
		request.setAttribute("map", map);
	%>
	<!-- 输出整个map -->
	${ map }<br>
	<!-- 输出单个map中a.a.a的值 , 但是输出不到,就是因为 .点运算符 的影响,它以为是a下的a下的a。-->
	${ map.a.a.a }
	<!-- 这个时候就用到了[]中括号运算符了 -->
	${ map['a.a.a']} 或者	${ map["a.a.a"] }   <br>
	${ map['b+b+b']} 或者	${ map["b+b+b"] }	<br>
	${ map['c-c-c']} 或者	${ map["c-c-c"] }	<br>
</body>
</html>

7. EL表达式 11个隐含对象

7.1 11个隐含对象


EL表达式的11个隐含对象,是它自己定义的(内置),可以直接使用。
在这里插入图片描述

7.2 EL 获取四个特定域中的属性


特定域属性特定域
pageScopepageContext域
requestScopeRequest域
sessionScopeSession域
applicationScopeServletContext域
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.ArrayList"%>
<%@ 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>
	<% 
		pageContext.setAttribute("key1", "pageContext1");
		pageContext.setAttribute("key2", "PageContext2");
		request.setAttribute("key1", "request1");
		request.setAttribute("key2", "request2");
		session.setAttribute("key1", "session1");
		session.setAttribute("key2", "session2");
		application.setAttribute("key1", "application1");
		application.setAttribute("key2", "application2");
	%>
	
	<!-- 如果调用默认的,那他自然是按照由小到大获取,只能获取到pageContext设置的属性: -->
	${ key1 } <br> ${ key2 }<br>
	
	*******************<br>
	
	<!-- 我们想要获得其他的就需要EL对应的四个内置对象了 -->
	${ pageScope.key1 }<br>
	${ pageScope.key2 }<br>
	${ requestScope.key1 }<br>
	${ requestScope.key2 }<br>
	${ sessionScope.key1 }<br>
	${ sessionScope.key2 }<br>
	${ applicationScope.key1 }<br>
	${ applicationScope.key2 }<br>
	
</body>
</html>

7.3 pageContext 使用


pageContext使用跟正常使用没什么差别,方法就是正常的通过对应的get方法来调用方法。

<%@ 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>

	------------<br>

	<!-- request.getScheme()方法:可以获取它可以获取请求的协议。 -->
	<%=request.getScheme() %><br>
	1.协议:${ pageContext.request.scheme }<br>
	
	------------<br>
	
	<!-- request.getServerName方法:获取服务器ip -->
	<%=request.getServerName() %><br>
	2.服务器ip:${ pageContext.request.serverName }<br>
	
	------------<br>
	
	<!-- request.getServerPort():获取请求的服务器端口号 -->
	<%=request.getServerPort() %><br>
	3.服务器端口:${ pageContext.request.serverPort }<br>
	
	------------<br>
	
	<!-- request.getContextPath()方法:获取当前工程路径 -->
	<%=request.getContextPath() %><br>
	4.获取工程路径:${ pageContext.request.contextPath }<br>
	
	------------<br>
	
	<!-- request.getMethod()方法:获取当前方法名 -->
	<%=request.getMethod() %><br>
	5.获取请求方法:${ pageContext.request.method }<br>
	
	------------<br>
	
	<!-- request.getRemoteHost()方法:获取客户端的ip地址 -->
	<%=request.getRemoteHost() %><br>
	6.获取客户端ip地址:${ pageContext.request.remoteHost }<br>
	
	------------<br>
	
	<!-- session.getId()方法:获取session的id编号 -->
	<%=session.getId() %><br>
	7.获取会话id编号:${ pageContext.session.id }<br>
	
	------------<br>
</body>
</html>

在企业中,常用一种更为方便的方式来定义上面的信息,如下:

<%@ 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>

	<% 
		pageContext.setAttribute("req", request);
	%>
	
	${ req.scheme }<br>
	${ req.serverName }<br>
	<!-- 企业中,常用这种方式来简化代码复杂程度,更直观一些。 -->
</body>
</html>

7.4 剩余的6个隐含对象使用

7.4.1 param和paramValues使用


在这里插入图片描述

<%@ 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>

	<!-- param的使用:  它对应map<String , String> , 它可以获取浏览器端发送的参数。-->
	<!-- 仅仅写了param , 没有参数它输出{} , 有参数它输出{参数=参数值 , ...} -->
	${ param }<br>
	<!-- 想要输出参数中的特定的值, 浏览器端发送?username=zhangsan&age=18作为参数测验。  -->
	${ param.username } , ${ param.age }<br>
	
	<!-- paramValues的使用,它对应map<String , String[]> , 它可以获取多个值得使用用,例如:?hobby=eat&hobby=work。-->
	${ paramValues.hobby[0] }<br>
	${ paramValues.hobby[1] }<br>
	
	
</body>
</html>

请求网址测试如下:http://localhost:8080/EL_JSTL/a.jsp?username=zhangsan&age=18&hobby=eat&hobby=work

param和paramValues使用:

  • param的使用: 它对应map<String , String> , 它可以获取浏览器端发送的参数,但是对于重复的数据,例如:?hobby=eat&hobby=work 它只能获取单个。

  • paramValues的使用,它对应map<String , String[]> , 它可以获取多个值得使用用,例如:?hobby=eat&hobby=work。

7.4.2 header 和 headerValues


在这里插入图片描述

<%@ 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>

	<!-- header的作用就是获取请求头的内容 -->
	${ header } <br>
	<!-- 注意:有些key值,有特殊字符如-+等等,这些都要用[]中括号符号来判别。 -->
	${ header.user-agent } <br><!-- 因为中间有个-号,因此它会识别user断开了。 -->
	${ header['user-agent'] } <br><!-- 需要注意user-agent,这个需要用单引号来括起来 -->
	${ header.connection }<br>
	
	<!-- headerValues的作用获取所有请求头参数内容,形式和paramValues一样 -->
	${ headerValues }<br>
	${ headerValues['user-agent'][0] }
	
</body>
</html>
  • header的作用就是获取请求头的内容。
  • headerValues的作用获取所有请求头参数内容,形式和paramValues一样。

7.4.3 EL表达式 cookie使用


在这里插入图片描述

<%@ 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>

	<!-- 获取cookies,以及cookies的JSESSIONID。-->
	${ cookie }<br>
	${ cookie.JSESSIONID }<br>
	<!-- 记住,这调用的name和value,在方法中调用的就是getName和getValue。 -->
	${ cookie.JSESSIONID.name }<br>
	${ cookie.JSESSIONID.value }<br>
	
</body>
</html>

7.4.4 EL表达式 initParam


在这里插入图片描述

<%@ 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>

	<!-- initParam的作用就是获取我们在web.xml配置的context-param参数 -->
	${ initParam }<br>
	输出&lt;Context-param&gt;:${ initParam.username }<br>
	输出&lt;Context-param&gt;:${ initParam.password }<br>
	
</body>
</html>

在这里插入图片描述

  • initParam的作用就是获取我们在web.xml配置的context-param参数。

8. JSTL 标签库 概述


JSTL标签库 全称是指Jsp Standard Tag Library , JSP标准标签库。是由Apache组织提供的开源的免费的jsp标签。

JSTL标签库是一个不断完善的开发源代码的JSP标签库。

EL表达式主要是为了替代jsp中的表达式脚本。
而标签库是为了替换代码脚本。这样使得整个jsp页面变得更佳简洁。

在这里插入图片描述

上面的标签库:需要用taglib来导入:

(prefix是前缀的意思。)
在这里插入图片描述

9. JSTL 标签库


作用:用于简化和替换jsp页面上的java代码,如果不是JSTL那么使用for循环时,就只能一节一节的<%%>脚本代码块缝合起来的样子很麻烦!。

使用步骤:

  • 1.导入jstl相关jar包。
  • 2.引入标签库:taglib指令: <%@ taglib %>
  • 3.使用标签。

有关jstl的jar下载如下:
http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/

常用的JSTL标签:

  • if :相当于java代码的if语句。
  • choose:相当于java代码的switch语句。
  • foreach:相当于java代码的for语句。

对标签的解释:

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

prefix是前缀的意思,就是相当于给标签库起前缀名,前缀名通常命名为 c 。

对于后面内容uri属性,我们导入两个jar包后,自然会补齐。

在这里插入图片描述

10. c:if 标签


这里prefix前缀也是命名为c了。

c:if标签:

  • 1.属性:
    • test 是必须设置的属性,接受boolean 表达式。
    • 如果表达式为true,则显示if标签体内容;如果表达式为false,则不显示标签体内容。
    • 一般情况下,test属性值会结合el表达式一起使用。
  • 2.注意:
    • c:if标签是没有else的情况!
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ 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>
	
	<!-- 
		c:if标签
			1.属性:
				* test 是必须设置的属性,接受boolean 表达式。
					* 如果表达式为true,则显示if标签体内容;如果表达式为false,则不显示标签体内容。
					* 一般情况下,test属性值会结合el表达式一起使用。
			2.注意:
				* c:if标签是没有else的情况!
	-->
	<%
		//判断request域中的一个list集合是否为空,如果不为null则显示遍历集合。
		List list = new ArrayList();
		list.add("aaa");
		request.setAttribute("list", list);
	%>
	
	<c:if test="${ not empty requestScope.list }">
		<!-- 遍历list集合 -->
		<%=request.getAttribute("list") %>
	</c:if>
	
	<br>
	<%
		session.setAttribute("number", 10);
	%>
	
	<c:if test="${ sessionScope.number % 2 == 0 }">
		session的number数值为偶数
	</c:if>
</body>
</html>

11. c:choose 标签


c:choose标签:

  • 使用choose标签取出数字, 相当于switch声明。
  • 使用when标签做数字判断,相当于case。
  • otherwise标签做其他情况的声明, 相当于default。
<%@ 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>
	
	<!-- 
		完成数字编号对应星期几案例 
			1.域中存储一数字。
			2.使用choose标签取出数字,   相当于switch声明。
			3.使用when标签做数字判断,相当于case4.otherwise标签做其他情况的声明, 相当于default-->
	<% request.setAttribute("number", 8); %>
	<c:choose>
		<c:when test="${requestScope.number == 1}">星期一</c:when>
		<c:when test="${requestScope.number == 2}">星期二</c:when>
		<c:when test="${requestScope.number == 3}">星期三</c:when>
		<c:when test="${requestScope.number == 4}">星期四</c:when>
		<c:when test="${requestScope.number == 5}">星期五</c:when>
		<c:when test="${requestScope.number == 6}">星期六</c:when>
		<c:when test="${requestScope.number == 7}">星期七</c:when>
		<c:otherwise>星期八</c:otherwise>
	</c:choose>
</body>
</html>

12. c:foreach 标签


foreach:相当于java代码的for语句:

1.完成重复的操作

for(int i = 0;i < 10;i++){
}

  • 属性:
    • begin:开始值
    • end:结束值
    • var:临时变量(就是上面的i)
    • step:步长 (这个步长就是i++位置要修改的内容啥的)
    • varStatus:循环状态对象
      • (有两个方法调用index和count:
        index:容器中元素的索引,从0开始。
        count:循环次数,从1开始。
        )

2.遍历容器

List list;
for(User user : list){
}

  • 属性:
    • items:容器对象。
    • var:容器中元素的临时变量。
    • varStatus:循环状态对象
      • index:容器中元素的索引,从0开始。
      • count:循环次数,从1开始。
<%@page import="java.util.List"%>
<%@page import="java.util.ArrayList"%>
<%@ 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>
	<%-- 
		foreach:相当于java代码的for语句
			1.完成重复的操作
				for(int i = 0;i < 10;i++){
				
				}
				* 属性:
					begin:开始值
					end:结束值	
					var:临时变量(就是上面的i)
					step:步长	(这个步长就是i++位置要修改的内容啥的)	
					varStatus:循环状态对象
						(有两个方法调用index和count:
							index:容器中元素的索引,从0开始。
							count:循环次数,从1开始。
							)
			2.遍历容器
				List<User> list;
				for(User user : list){
				
				}
				* 属性:
					items:容器对象。
					var:容器中元素的临时变量。
					varStatus:循环状态对象
						index:容器中元素的索引,从0开始。
						count:循环次数,从1开始。
	 --%>
	 
	 <c:forEach begin="1" end="10" var="i" step="2" varStatus="s">
	 	${i}, ${ s.index } , ${ s.count }<br>
	 </c:forEach>
	 <br>
	 ------------
	 <br>
	 <%
	 	List list = new ArrayList();
	 	list.add("aaa");
	 	list.add("bbb");
	 	list.add("ccc");
	 	
	 	request.setAttribute("list", list);
	 %>
	 <c:forEach items="${ list }" var="str" varStatus="s">
	 	${ s.index }, ${ s.count } , ${ str }<br>
	 </c:forEach>
</body>
</html>

13. c:set 标签


<c:set /> 作用:set标签可以往域中保存数据。

作用:set标签可以往域中保存数据。

  • scope属性有四个对应值:
    • page表示PageContext域(默认值)。
    • request表示Request域。
    • session表示Session域。
    • application表示ServletContext域。
  • var属性:设置key。
  • value属性:设置值。
<%@page import="java.util.List"%>
<%@page import="java.util.ArrayList"%>
<%@ 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>
	<!-- 
		<c:set />
			作用:set标签可以往域中保存数据。	
			
			scope属性有四个对应值:
				page表示PageContext(默认值)
				request表示Request域。
				session表示Session域。
				application表示ServletContext域。
			var属性:设置key。
			value属性:设置值。
	-->
	 保存之前:${ requestScope.abc }<br>
	 <c:set scope="request" var="abc" value="zhangsan"/>
	保存之后:${ requestScope.abc }<br>
</body>
</html>

14. 文件的上传

14.1 文件的上传 说明


步骤如下:

  • 1.要有一个form标签,method=post请求。
  • 2.form标签的encType属性值必须为multipart/form-data值。
  • 3.在form标签中使用input type=file添加上传的文件。
  • 4.编写服务器代码(Servlet程序)接受,处理上传的数据。

encType=multipart/form-data 表示提交的数据,以多段(每一个表单项一个数据段)的形式进行拼接,然后以二进制流的形式发送给服务器。

multipart/form-data格式的http请求体如下:
在这里插入图片描述


平时,我们默认的发送数据都是下面这种类型:
在这里插入图片描述


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>
	<form action="http://localhost:8081/EL_JSTL/touxiang" method="post" enctype="multipart/form-data">
		用户名:<input type="text" name="username"/> <br>
		头像:<input type="file" name="phone"/><br> 
		<input type="submit" value="上传">
	</form>
</body>
</html>

<input type=“file” name=“phone”/> , file类型要记一下!

Servlet代码:

package com.test;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/touxiang")
public class touxiang extends HttpServlet{
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println("文件上传中....");
		
		//首先,我们传入的参数并不是application/x-www-form-urlencoded , 因此接收不到参数
		//System.out.println(req.getParameter("username"));
		//System.out.println(req.getParameter("photo"));
		
		//我们使用流的方式来接受内容
		ServletInputStream inputStream = req.getInputStream();
		
		byte[] buffer = new byte[1024];
		int read = inputStream.read(buffer);
		
		while(read!=-1) {
			System.out.println(new String(buffer,0,read));
			read = inputStream.read(buffer);
		}
		
	}
}

在这里插入图片描述

14.2 commons-fileupload.jar 常用API介绍和使用


我们上传文件需要commons-fileupload.jar包,而它需要依赖commons-io.jar这个包,所以两个包我们都要引入。

commons-fileupload.jar中的ServletFileUpload类:就是用来解析上传的数据;
FileItem类:表示每一个表单项。


commons-fileupload.jar和commons-io.jar包中我们常用的方法:

在这里插入图片描述

文件上传的大体思路:

package com.test;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

@WebServlet("/uploadServlet")
public class UploadServlet extends HttpServlet {
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 先判断上传的数据是否多段数据(只有是多段数据,才是文件上传的)
		if (ServletFileUpload.isMultipartContent(req)) {

			// 创建FileItemFactory工厂实现类
			FileItemFactory failItemFactory = new DiskFileItemFactory();
			// 创建用于解析上传数据的工具类ServletFileUpload类
			ServletFileUpload servletFileUpload = new ServletFileUpload(failItemFactory);

			try {
				// 解析上传的数据,得到每一个表单项FileItem。
				List<FileItem> list = servletFileUpload.parseRequest(req);

				// 循环判断,每一个表单项,是普通类型,还是上传的文件。
				for (FileItem fileItem : list) {
					if (fileItem.isFormField()) {

						// 返回true,普通表单项:
						// 查看当前表单的name:
						System.out.println("表单项的name属性值:" + fileItem.getFieldName());
						// 查看当前表单的value:(UTF-8是用来解决乱码问题)
						System.out.println("表单项的value属性值:" + fileItem.getString("UTF-8"));

					} else {

						// 返回false,上传的文件
						System.out.println("表单项的name属性值:" + fileItem.getFieldName());
						System.out.println("上传的文件名:" + fileItem.getName());

						try {
							fileItem.write(
									new File("D:\\java_environment_tools\\eclipse_project\\EL_JSTL\\WebContent\\image\\"
											+ fileItem.getName()));
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}

				}

			} catch (FileUploadException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

	}
}

15. 文件的下载

15. 文件下载的 基本过程


步骤如下:
在这里插入图片描述
安装上图步骤一步一步来:(这里我们一访问该servlet对应的url,就会下载)

package com.test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet{
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		//1.获取要下载的文件名
		String downloadFileName = "头像.png";
		
		//2.读取要下载的文件内容(通过ServletContext对象可以读取)
		ServletContext servletContext = getServletContext();
		//获取要下载的文件类型
		String mimeType = servletContext.getMimeType("/image/"+downloadFileName);
		System.out.println(mimeType);
		
		//4.在回传前,通过响应头告诉客户端返回的数据类型
		resp.setContentType(mimeType);
		
		//5.还要告诉客户端收到的数据是用于下载使用(这里依然通过响应头使用)
		//Content-Disposition: 这个属性,表示收到的数据怎么处理。
		//attachment表示附件
		//filename=文件名 :表示指定下载的文件名 
		resp.setHeader("Content-Disposition", "attachment;filename="+downloadFileName);
		
		//再次解释一下' / '斜杆被服务器解析表示地址为http://ip:port/工程名/ 映射到WebContent目录下
		InputStream resourceAsStream = servletContext.getResourceAsStream("/image/"+downloadFileName);
		
		//获取响应的输出流
		OutputStream outputStream = resp.getOutputStream();
		
		//平时我们是创建一个字节数组然后调用read向客户端发送数据,
		//3.现在,我们使用commons-io jar包下的IOUtils.copy()方法,这个方法将resourceAsStream内容复制给了outputStream。
		IOUtils.copy(resourceAsStream, outputStream); //读取输入流中全部的数据,复制给输出流,输出给客户端。
		
		
		
	}
}

15.2 URL编码 解决谷歌和IE浏览器中文下载乱码


我们上面发送的汉字:头像.png,查看控制台时发现:
在这里插入图片描述


我们在设置请求头时,可以使用URLEncoder.encode()方法来编译:

resp.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(downloadFileName,"UTF-8"));

URLEncoder.encode()编码就叫做url编码,就把汉字转成了%xx%xx的格式。

牢记url编码格式仅仅适用于谷歌和IE浏览器。

15.3 BASE64编码 解决火狐浏览器中文乱码


15.3.1 BASE64 编码解码过程


base64编解码操作如下:

package com.test;

import java.io.IOException;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class BASE64 {
	public static void main(String[] args) throws IOException {
		//base64的编码操作:
		String content = "这是需要base64编码的内容";
		//1.创建base64编码器:base64Encoder
		BASE64Encoder base64Encoder = new BASE64Encoder();
		//2.将内容进行编码
		String encode = base64Encoder.encode(content.getBytes());
		System.out.println(encode);
		
		//base64的解码操作:
		//1.创建base64解码器:base64Decoder
		BASE64Decoder base64Decoder = new BASE64Decoder();
		//2.将内容进行解码,这里得到字节数组
		byte[] decodeBuffer = base64Decoder.decodeBuffer(encode);
		//3.再将字节数组还原成字符串
		String content02 = new String(decodeBuffer,"UTF-8");
		System.out.println(content02);
	}
}

15.3.2 base64 解决火狐浏览器中文乱码


在这里插入图片描述
按照BASE64编码过程来设置请求头:

resp.setHeader("Content-Disposition", "attachment;filename==?UTF-8?B?"+new BASE64Encoder().encode(downloadFileName.getBytes("UTF-8"))+"?=");
package com.test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

import sun.misc.BASE64Encoder;

@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet{
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		//1.获取要下载的文件名
		String downloadFileName = "头像.png";
		
		//2.读取要下载的文件内容(通过ServletContext对象可以读取)
		ServletContext servletContext = getServletContext();
		//获取要下载的文件类型
		String mimeType = servletContext.getMimeType("/image/"+downloadFileName);
		System.out.println(mimeType);
		
		//4.在回传前,通过响应头告诉客户端返回的数据类型
		resp.setContentType(mimeType);
		
		//5.还要告诉客户端收到的数据是用于下载使用(这里依然通过响应头使用)
		//Content-Disposition: 这个属性,表示收到的数据怎么处理。
		//attachment表示附件
		//filename=文件名 :表示指定下载的文件名 
		//resp.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(downloadFileName,"UTF-8"));
		resp.setHeader("Content-Disposition", "attachment;filename==?UTF-8?B?"+new BASE64Encoder().encode(downloadFileName.getBytes("UTF-8"))+"?=");
		
		//再次解释一下' / '斜杆被服务器解析表示地址为http://ip:port/工程名/ 映射到WebContent目录下
		InputStream resourceAsStream = servletContext.getResourceAsStream("/image/"+downloadFileName);
		
		//获取响应的输出流
		OutputStream outputStream = resp.getOutputStream();
		
		//平时我们是创建一个字节数组然后调用read向客户端发送数据,
		//3.现在,我们使用commons-io jar包下的IOUtils.copy()方法,这个方法将resourceAsStream内容复制给了outputStream。
		IOUtils.copy(resourceAsStream, outputStream); //读取输入流中全部的数据,复制给输出流,输出给客户端。
		
	}		
}

16. 判断浏览器类型


上面说到不同浏览器对应不同的编码解码方式,那么怎么判断他们的浏览器类型呢?

我们请求头里面有个User-Agent,从这里面就可以获得到浏览器的信息。

//我们可以通过User-Agent来判断是否是火狐浏览器还是别的浏览器,进而使用不同的编码格式
if(req.getHeader("User-Agent").contains("FireFox")) {
	resp.setHeader("Content-Disposition", "attachment;filename==?UTF-8?B?"+new BASE64Encoder().encode(downloadFileName.getBytes("UTF-8"))+"?=");
}else {
	resp.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(downloadFileName,"UTF-8"));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xupengboo

你的鼓励将是我创作最大的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值