一.Servlet3.0 注解
在 Servlet3.0 之前一直使用的都是配置文件的方式来实现各种组件,Servlet3.0 之后提供了注解,可以达到零配置。但现实中一般是注解+配置结合使用。我们看几个常用的注解。
1. @WebServlet
开发servlet项目,使用@WebServlet将一个继承于javax.servlet.http.HttpServlet 的类定义为Servlet组件。在Servlet3.0中 , 可以使用@WebServlet注解将一个继承于javax.servlet.http.HttpServlet的类标注为可以处理用户请求的 Servlet。
用注解配置 Servlet
@WebServlet(name="ServletDemo",value="/servletDemo")
也可以配置多个 urlPatterns 来指定多个访问路径
@WebServlet(name="ServletDemo",urlPatterns={"/servletDemo","/servletDemo2"})
2. @WebFilter
@WebFilter 用来配置过滤器
@WebFilter(filterName="TestFilter",urlPatterns="/*")
3. @WebListener
Servlet3.0 提供@WebListener 注解将一个实现了特定监听器接口的类定义为监听器。将 实现了 ServletContextListener 接口的 MyServletContextListener 标注为监听器。
4. @MultipartConfig
使用注解@MultipartConfig 将一个 Servlet 标识为支持文件上传。 Servlet3.0 将 multipart/form-data 的 POST 请求封装成 Part,通过 Part 对上传的文件进行操作。
二.Servlet3.0
Servlet3.0 将 multipart/form-data 的 POST 请求封装成 Part,通过 Part 对上传的文件进行操作
package com.shsxt.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 使用注解@MultipartConfig 将一个 Servlet 标识为支持文件上传。
Servlet3.0 将 multipart/form-data 的 POST 请求封装成 Part,通过 Part 对上传的文件进行操作。
* @author Lisa Li
*
*/
@WebServlet("/upload")
@MultipartConfig // 表示支持文件上传 注:如果前台表单提交时的表单类型为enctype="multipart/form-data",后台必须要加@MultipartConfig注解!!!!!
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取普通参数
String name = request.getParameter("uname");
System.out.println(name);
// 得到Part对象
// request.getPart(name):name代表的是前台文件域的name属性值
/*Part part = request.getPart("myfile");
// 得到上的文件名
String fileName = part.getSubmittedFileName();
// 通过上传的文件名是否为空可以判断是否上传了文件
if (fileName == null || "".equals(fileName)) {
// 未上传文件
return;
}
// 得到文件存放路径
String realPath = request.getServletContext().getRealPath("/");
// 上传文件到指定路径
part.write(realPath + fileName);
*/
}
}
三.请求乱码问题
Tomcat8及以上版本 | Tomcat7及以下版本 | |
POST请求 | 会乱码,request.setCharacterEncoding("UTF-8"); | 会乱码,request.setCharacterEncoding("UTF-8"); |
GET 请求 | 不会乱码,不处理 | 会乱码,new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8"); |
package com.shsxt.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
@WebFilter("/*")
public class EncodeFilter implements Filter {
public EncodeFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException {
// 基于HTTP
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
// 处理POST请求乱码 (无论什么版本服务器)
request.setCharacterEncoding("UTF-8");
// 处理GET请求乱码
// 1、得到请求类型
String method = request.getMethod();
// 2、判断是否是GET请求
if ("GET".equalsIgnoreCase(method)) {
// 3、如果是GET请求,则获取服务器版本信息
String serverInfo = request.getServletContext().getServerInfo();
//System.out.println(serverInfo);
// 4、得到服务器的版本号
String versionStr = serverInfo.substring(serverInfo.lastIndexOf("/")+1,serverInfo.lastIndexOf("/")+2);
// 5、判断是否是Tomcat8以下版本服务器
if (Integer.parseInt(versionStr) < 8) {
// new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");
// 定义类,继承HttpServletRequestWrapper封装类,重写getParameter()方法,返回的类的本质是request对象
HttpServletRequest req = new MyWapper(request);
// 放行指定request对象 (Ttomcat7及以下版本的GET请求)
chain.doFilter(req, response);
return;
}
}
// POST请求和Ttomcat8及以上版本的GET请求放行
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
/**
* 1、定义类
* 2、继承HttpServletRequestWrapper封装类
* 3、重写getParameter()方法
*
* @author Lisa Li
*
*/
class MyWapper extends HttpServletRequestWrapper {
// 定义属性。提升作用域
private HttpServletRequest request;
/**
* 带参构造器
* @param request
*/
public MyWapper(HttpServletRequest request) {
super(request);
this.request = request;
}
/**
* 重写getParameter()方法,处理乱码问题
*/
@Override
public String getParameter(String name) { // name代表的是前台传递的参数名,即键
// 获取参数的值
String value = request.getParameter(name);
// 判断值是否为空,不为空处理乱码问题
if (value == null || "".equals(value.trim())) {
return value;
}
try {
// 处理乱码问题
value = new String(value.getBytes("ISO-8859-1"),"UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
}
四.JSP
1.配置Eclipse
这一步不是必须的,当然由于 eclipse 中有写默认的配置项我们觉得不是很完美,比如 字符编码,比如 HTML 的 DOCTYPE,我们可以在新建 JSP 页面之前就先修改为我们需要的。
最后一路保存,关闭即可
2. 新建 JSP 文件
新建完成以后的完整代码如下:
3.JSP基础语法
1)注释
在 JSP 中支持两种注释的语法操作,一种是显示注释,这种注释是允许客户端看见的; 另一种是隐式注释,此种注释是客户端无法看见的
① 显示注释语法:从 HTML 风格继承而来
② 隐式注释语法:从 JAVA 风格继承;JSP 自己的注释
JSP 的三种注释方式:
① // 注释,单行注释 /* 多行注释*/
② <!-- HTML风格的注释 -->
③<%-- JSP注释 --%>
2)Scriptlet
在 JSP 中最重要的部分就是 Scriptlet(脚本小程序),所有嵌入在 HTML 代码中的 Java 程序都必须使用 Scriptlet 标记出来,在 JSP 中一共有三种 Scriptlet 代码:
第一种:<% %>: java 脚本段,可以定义局部变量、编写语句
第二种:<%! %>:声明,可以定义全局(成员)变量、方法、类
第三种:<%= %>:表达式,数据一个变量或具体内容
通过观察解析为 java 文件的 jsp 代码理解三种小脚本
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>JSP的使用</h2>
<%
String str = "Hello JSP";
System.out.println(str);
response.getWriter().write(str);
%>
<%!
String memberStr="a member String";
%>
<%=memberStr%>
<h1>This is a JSP page!</h1>
</body>
</html>
4.JSP指令标签
page指令
language:支持的语言,目前只有java
contentType:响应类型及编码格式
pageEncoding:字符编码
import:导包,只有该属性可以同时设置多次
errorPage:当页面报错时要跳转的页面,一般与isErrorPage属性一起使用,且跳转的页面的isErrorPage属性设置为true
isErrorPage:是否是处理错误的页面,默认是false。一般与errorPage属性一起使用
注:页面的编码以charset的值为准;若charset未设置,则以pageEncoding为准;若两者都未设置,则使用默认编码ISO-8859-1
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
import="java.util.List" import="java.util.ArrayList" isErrorPage="false" %>
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP指令标签</title>
</head>
<body>
<%
List<String> list = new ArrayList<>();
/* int a = 1/0; */
%>
</body>
</html>
5.include静态包含和动态包含
1)include静态包含
格式:<%@include file="文件路径" %> 相对路径
file属性支持表达式去取值
特点:只会生成一个源码文件,相当于直接将内容拷贝进来,所以不能有同名变量。
运行效率高一点点。耦合性较高,不够灵活。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>include静态包含</title>
</head>
<body>
<div style="height: 800px;width:800px">
<div id="left" style="width: 200px;height:800px;background-color: pink;float: left;">
<%@include file="left.jsp" %>
</div>
<div id="right" style="width: 600px;height:800px;background-color: gray;float: left;">
<%@include file="right.jsp" %>
</div>
</div>
<%
// int a = 1;
%>
</body>
</html>
2)include动态包含
语法:<jsp:include page="要包含的文件路径"></jsp:include>
page属性支持表达式去取值
特点:生成多个源码文件,相当于方法的调用,可以有同名变量。
耦合度低,比较灵活,效率高。
注:
①<jsp:include>双标签之间不能有任何内容(除非有参数)
Expecting "jsp:param" standard action with "name" and "value" attributes
②动态包含可以传递参数
<jsp:param name="参数名" value="参数值"/>
获取参数使用:request.getParameter(name)
value属性支持表达式,name属性不支持
The name attribute of the jsp:param standard action does not accept any expressions
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>include动态包含</title>
</head>
<body>
<%
int a =10;
String key = "userName";
String val = "admin";
%>
<div style="height: 800px;width:800px">
<div id="left" style="width: 200px;height:800px;background-color: blue;float: left;">
<jsp:include page="left.jsp"></jsp:include>
<jsp:include page="left.jsp">
<jsp:param value="<%=val %>" name="uname"/>
</jsp:include>
</div>
<div id="right" style="width: 600px;height:800px;background-color: green;float: left;">
<jsp:include page="right.jsp"></jsp:include>
</div>
</div>
</body>
</html>
6.九大内置对象
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
// 四大域对象
pageContext.setAttribute("uname1", "zhanggsan");
//request
// session
// application
// 两个输出对象
// out
// response
// 配置对象
// config
// 当前页面对象
//page
// 异常对象 主要当前页面设置了isErrorPage="true"时才能使用
// exception
%>
</body>
</html>
五.EL表达式
语法:${key } key代表的是存在域对象中的键
注意:el表达式一般操作的是域对象,无法操作变量
取值范围:
从小范围到大范围取,取到为止,若未取到,则一直向大返回查找;若四个范围都未获取到,返回空字符串。
获取指定范围的值:
pageScope、requestScope、sessionScope、applicationScope
pageContext, request, session, application;范围依次是,本页面,一次请求, 一次会话,整个应用程序。
而 EL 默认的查找方式为 从小到大查找,找到即可。当域对象全 找完了还未找到则返回空字符串””。
EL操作对象
获取对象中的属性:${对象.属性名}
注:属性必须提供get和set方法
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@page import="com.shsxt.model.User"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>EL表达式</title>
</head>
<body>
<%
// 设置域对象的值
pageContext.setAttribute("uname", "zhangsan");
request.setAttribute("uname", "lisi");
session.setAttribute("uname", "wangwu");
application.setAttribute("uname", "zhaoliu");
String str = "admin";
// 将对象存到域对象中
User user = new User();
user.setUserId(1);
user.setUserName("Lisa");
user.setUserPwd("123123");
request.setAttribute("user", user);
// 将集合存到域对象中
User user2 = new User();
user2.setUserId(2);
user2.setUserName("Lily");
user2.setUserPwd("123456");
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
List<User> userList = new ArrayList<>();
userList.add(user);
userList.add(user2);
List<String> list2 = new ArrayList<>();
List<String> list3 = null;
request.setAttribute("mylist", list);
request.setAttribute("userList", userList);
request.setAttribute("list2", list2);
request.setAttribute("list3", list3);
Map map = new HashMap();
map.put("aaa", "111");
map.put("bbb", 2222);
map.put("ccc-a", 333);
request.setAttribute("map", map);
request.setAttribute("num", 10);
request.setAttribute("num2", 2);
request.setAttribute("str1", "aa");
request.setAttribute("str2", "bb");
pageContext.setAttribute("a", "aa", PageContext.REQUEST_SCOPE);
pageContext.getAttribute("a", PageContext.REQUEST_SCOPE);
%>
<%=request.getAttribute("uname1") %>
<hr>
<br>
<h2>EL的基本使用</h2>
uname:${uname } <br>
uname1: ${uname1 }<br>
requestScope:${requestScope.uname } <br>
str:${str }<br>
<br><br>
<h2>EL 对象取值</h2>
user对象:${user }<br>
获取user对象中的属性:${user.userName }<br>
<h2>EL 集合取值</h2>
获取集合:${mylist } ---- ${userList }<br>
获取指定下标的值: ${mylist[0] } ---- ${userList[0].userPwd }<br>
获取集合的长度:${userList.size() }
<h2>判断为空empty</h2>
判断字符串是否为空:${empty uname } --- ${empty uname1 } --- ${!empty uname }<br>
判断对象是否为空:${empty user }<br>
判断集合是否为空:${empty userList } --- ${empty list2 } --- ${empty list3 }<br>
<h2>EL Map取值</h2>
获取Map的值:${map }<br>
获取指定key的value:${map.aaa } --- ${map["aaa"] }<br>
<h2>EL 运算</h2>
${1+1 } -- ${num+1 } -- ${num + num2 } <br>
${num / num2 } ---
<%-- ${num div num2 } --%>
<br>
<h2>EL 比较</h2>
${num == 1 } -- ${num >= 10 } <br>
${str1 == str2 } -- ${str1 eq str2 }<br>
${num + 10 > 10 }
</body>
</html>
六.JSP内置对象四种属性范围(重点)
目标
⑴掌握属性的操作方法
⑵掌握JSP中的四种属性范围的作用
⑶掌握pageContext对象设置四种属性范围的方法
四种属性范围
在JSP中提供了四种属性的保存范围,所谓的属性保存范围,指的就是一个设置的对象,可以再多少个页面中保存并可以继续使用
page范围→pageContext : 只在一个页面中保存属性,跳转之后无效
request范围→request : 只在一次请求中保存,服务器跳转后依然有效
session范围→session : 在一次会话范围中,无论何种跳转都可以使用,但是新开浏览器无法使用
application范围→application : 在整个服务器上保存,所有用户都可以用
属性都有的操作方法
验证各个属性范围的特点
page: 本页面取得服务器端跳转(<jsp :forward>)后无效
request : 服务器跳转(<jsp :forward>)有效,客户端跳转(超链接)无效
如果是客户端跳转,则相当于发出了两次请求,那么第一次的请求将不存在了
如果希望不管是客户端还是服务器跳转,都可以保存的话,就需要继续扩大范围。
session : 无论客户端还是服务器端都可以取得,但是现在重新开启一个新的浏览器,则无法取得之前设置的session了,因为每一个session只保存在当前的浏览器当中,并在相关的页面取得。
对于服务器而言,每一个连接到它的客户端都是一个session
如果想要让属性设置一次之后,不管是否是新的浏览器打开都能取得则可以使用application
application : 所有的application属性直接保存在服务器上,所有的用户(每一个session)都可以直接访问取得
只要是通过application设置的属性,则所有的session都可以取得,表示公共的内容,但是如果此时服务器重启了,则无法取得 了,因为关闭服务器后,所有的属性都消失了,所以需要重新设置。
使用哪个范围呢?在合理范围尽可能小
page范围
page范围是通过pageContext对象设置的,之前研究过的page属性范围中使用的是pageContext进行属性设置的,但是 从javax.servlet.jsp.PageContext类中可以发现,有以下的一种设置属性的方法:
public void setAttribute(String name, Object value, int scope)
在PageContext类中存在四个表示属性范围的常量,可以直接通过这些常量指定scope:
pageContext.PAGE_SCOPE
pageContext.REQUEST_SCOPE
pageContext.SESSION_SCOPE
pageContext.APPLICATION_SCOPE
在其它页面取值时,需要指定对应的作用域,或者通过EL表达式
<%=pageContext.getAttribute("a",pageContext.SESSION_SCOPE) %>