9大默认对象
JSP容器根据servlet API而提供了某些隐含对象。可以使用标准的变量来访问这些对象,可以在JSP页面直接使用这九大对象
page this 封装页面对象,是Object类型的,该对象代表了正在运行的由JSP文件产生的类对象,相当于this。一般情况下不建议使用该对象
是Object类型的,所以可以合法调用的方法都是Object中定义的方法
toString equals hashcode wait notify notifyAll
在jsp页面种声明了一个方法pp
<%! public void pp(){} %> //页面种进行调用 <% page.pp(); %> 语法错误,因为page是Object类型的,所以按照Object进行检查 <% this.pp(); %> 语法正确
request ServletRequest,封装请求对象,代表的是来自客户端的请求HttpServletRequest。包括从GET/POST请求传递过来的参数
封装的数据有3部分: header parameter attribute
getHeader(“Accept”):String getIntHeader getDateHeader
getParameter(“name”):String getParameterValues(“hobby”):String[]
setAttribute(“name”,Object) getAttribute(“name”) removeAttribute(“name”)
上传数据
1、表单
<form method="post" enctype="multipart/form-data">
2、在Servlet中则可以通过getInputStream或者getReader获取输入流以处理客户端启动的文件
3、引入jspSmartupload组件简化上传处理开发
getRequestDisapatcher(“bbb.jsp”).forward(request,response)
- 地址栏不变
- 共享request
response ServletResponse,封装响应对象,代表的是对客户端的响应HttpServletResponse。网页传回客户端的信息
设置响应头
setHeader(“name”,“value”) setIntHeader setDateHeader
- 避免客户端缓存
- 以附件方式打开
setContentType(“text/html;charset=utf-8”)
MIME多用途互联网邮件扩展—用来识别文件内容类型 text/html image/jpeg
getWriter() getOutputStream()
response.sendRedirect(“bb.do”); 重定向
- 地址栏自动变化
- 不共享request
application ServletContext,封装应用程序对象,负责提供应用程序在服务器中运行时的一些全局信息,是一个容器级的共享对象数据
session HttpSession 封装会话对象,代表服务器与客户端所建立的会话,在不同的JSP页面中保留客户信息的情况下用于跟踪用户状态
config ServletConfig 封装代码配置对象,该对象提供一些该Servlet的配置信息,是javax.servlet.ServletConfig接口的实现
getInitParameter(“name”):String
web.xml
<servlet> <servlet-name>index1</servlet-name> <jsp-file>/index.jsp</jsp-file> <init-param> <param-name>name</param-name> <param-value>yanjun</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>index1</servlet-name> <url-pattern>/bbb.do</url-pattern> </servlet-mapping>
exception 异常信息的对象,封装异常对象,代表了JSP文件运行时所产生的并且没有被捕获的例外对象,此对象不能在一般JSP文件中直接使用,而只能在使用了<%@ page isErrorPage="true "%>
的JSP文件中使用
在页面种使用exception默认对象的要求当前页面必须配置
<%@ page isErrorPage="true "%>
<%=exception%> <%=exception.getMessage()%> <% exception.printStackTrace(new PrintWriter(out)); %>
out 等价于response.getWriter() 封装输出对象,用来向客户端自定义输出内容,代表了向客户端发送数据的对象,是javax.servlet.jsp.JspWriter接口的实现。JspWriter是带缓冲的版本
out.println("…")/print("…")/newLine()------
out.println("<br/>");
pageContext 包装页面上下文对象,代表的是当前页面运行的一些属性,例如可以获取session、request、response、exception、ServletContext和ServletConfig的引用。是javax.servlet.jsp.PageContext接口的实现
application对象
application对象实现了用户间数据的共享,可存放全局变量。它开始于服务器的启动,直到服务器的关闭,在此期间,此对象将一直存在;这样在用户的前后连接或不同用户之间的连接中,可以对此对象的同一属性进行操作;在任何地方对此对象属性的操作,都将影响到其他用户对此的访问。服务器的启动和关闭决定了application对象的生命。它是ServletContext类的实例
获取application对象的引用
getServletConfig().getContext()
request.getSession().getServletContext()
一般注意引用application 变量进行修改操作时,必须使用同步。并且,需要测试一个application属性是否已经存在
- 因为一个应用对应一个application对象,是访问当前应用的所有用户共享
- 一个服务器中可以部署多个应用
常规方法:
1、作为容器在多用户之间共享数据的方法
setAttribute(“name”,Object) getAttribute removeAttribute
2、获取指定文件或者文件夹的绝对路径
String str=application.getRealPath(""); //获取当前当前应用所在根目录的路径
String str=application.getRealPath("/upload/"); //获取当前当前应用所在根目录下的upload文件夹的绝对路径
- 查找文件夹一定会有返回值,和文件夹是否存在没有关联
<%@ page import="java.io.File" %>
<%
String str=application.getRealPath("/upload/");
File ff=new File(str);
if(!ff.exists())
ff.mkdirs();
%>
3、获取上下文的初始化参数
web.xml
<context-param>
<param-name>counter</param-name>
<param-value>123</param-value>
</context-param>
获取方法
Object obj=application.getInitParameter("counter");
out.println(obj);
4、用于读取应用路径下的文件
InputStream is=application.getResourceAsStream("bb.properties"); //该文件位于webapp根目录下
Properties ps=new Properties();
ps.load(is);
String val=ps.getProperty("abc");
out.println(val);
最终练习:计数器的实现1 – 功能不完善
servlet负责准备需要显示的数据
public class WelcomeServlet extends HttpServlet {
@Override
public void init() throws ServletException {
//读取xml配置的初始化参数值
//这是这个Servlet的独有配置信息,就是<servlet>标签的子标签
String s1=this.getServletConfig().getInitParameter("counter");
long l1= IntUtils.converterLong(s1);
//这个是当前应用范围内所有Servlet都可以读取的全局配置参数
String s2=this.getServletContext().getInitParameter("counter");
long l2=IntUtils.converterLong(s2);
l2=Math.max(l1,l2);
//读取properties文件中的计数值
long l3=0;
InputStream is=this.getServletContext().getResourceAsStream("counter.data");
if(is!=null){
DataInputStream dis=new DataInputStream(is);
try {
l3=dis.readLong();
l2=Math.max(l2,l3);
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//比较两次的计数值,将较大的值存储在application中
this.getServletContext().setAttribute("counter",l2);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("welcome.jsp").forward(request,response);
}
}
jsp页面显示数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<%! //声明代码段中不能直接使用9大默认对象,定义方法需要传递参数
String add(ServletContext application) {
Long l1 = 0L;
synchronized (application) {
Object ll = application.getAttribute("counter");
if (ll != null && ll instanceof Long)
l1 = (Long) ll;
l1++;
application.setAttribute("counter", l1);
}
StringBuilder sb=new StringBuilder();
String ss=l1+"";
for(int i=0;i<ss.length();i++){
sb.append("<img src='images/"+ss.charAt(i)+".png'>");
}
return sb.toString();
}
%>
</head>
<body>
<%=this.add(application)%>
</body>
</html>
session
session对象指的是客户端与服务器的一次会话,从客户端连到服务器的一个Web Application开始,直到客户端与服务器断开连接为止。它是HttpSession类的实例,一个浏览器窗口对应一个session
1、实现在当前应用中跨页面数据传输
session.setAttribute(“name”,Object) getAttribute(“name”):Object removeAttribute(“name”)
2、session数据存储在服务器端,所以需要有一个标识值用于区分不同用户。这个值存储在客户端的内存Cookie中session.getId():String
3、清空session,例如退出登录
session.invalidate() 清空session对象里的东西,并不指清除这个session对象本身
用户登录成功后需要有一种标志表示当前用户已经登录
- session.setAttribute(“user”,user);
退出登录
- session.invalidate();
4、针对非正常退出应用,针对session有个超时设置
web.xml
<session-config> <session-timeout>30</session-timeout> 这里的单位为分钟,Tomcat即使不作配置,默认就是30分钟 </session-config>
一般如果安全性要求高,则时长设置短一些;如果要求对客户友好,则时长设置长一些
session.getCreateTime()
5、if(!session.isNew()) name=(String)session.getAttribute(“username”);
需求:猜测数字
定义Servlet的doGet方法用于生成一个猜数目标值
- 采用request传递数据,则为了跟踪记录目标值,则需要使用隐藏域—安全性低
- 采用session实现多页面之间的数据共享
- 采用application数据共享是不合理的,因为application适用于跨用户数据共享,但是这里实际上是不同用户猜自己的目标值
实际上传递数据有4种领域<jsp:useBean id="now" class="java.util.Date" scope="page/request/session/application"/>
- page只在当前页面范围内有效
- request在请求转发时可以在多个页面之间共享数据
- session针对单一用户的跨页面数据共享
- application在当前应用范围内跨用户数据共享
选择依据:范围越小越好,因为范围小时会自动垃圾回收,以避免手工管理,同时解决内存空间
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Random r=new Random();
int target=r.nextInt(900)+100;
HttpSession session=request.getSession();
//考试点 request.getSession(boolean)和request.getSession()之间的区别:
/* getSession()等价于getSession(true)表示获取和当前用户相关的session对象,如果有则重用;如果没有则新建
getSession(false)表示有则重用,如果没有不会新建,返回null
一般从应用编程方面来说,使用getSession()方法
*/
session.setAttribute("target",target);
request.getRequestDispatcher("input.jsp").forward(request,response);
}
jsp显示表单,要求用户录入数据
<form action="guess.do" method="post">
<input name="num"/>
<input type="submit" value="验证"/>
</form>
Servlet接收数据
- 接收数据 request.getParameter
- 数据校验
- 调用javaBean完成业务逻辑处理
- 根据业务方法的执行结果跳转对应的页面
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String ss = request.getParameter("num");
Map<String, String> map = new HashMap<>();
Integer num = null;
try {
num = Integer.parseInt(ss);
} catch (Exception e) {
map.put("num", "输入数据不合法!");
}
if (map.size() > 0) {
request.setAttribute("error", map);
request.getRequestDispatcher("input.jsp").forward(request, response);
return;
}
//业务逻辑处理
HttpSession session = request.getSession();
Integer target = null;
Object obj = session.getAttribute("target");
if (obj != null && obj instanceof Integer) {
target = (Integer) obj;
List<Integer> list = new ArrayList<>();
if (target == num) {
request.setAttribute("msg", "猜对了!");
} else {
Object obj2=session.getAttribute("history");
if(obj2!=null && obj2 instanceof List)
list=(List<Integer>)obj2;
list.add(num);
session.setAttribute("history",list);
if (target > num)
request.setAttribute("msg", "猜小了!");
else if (target < num)
request.setAttribute("msg", "猜大了!");
}
request.getRequestDispatcher("input.jsp").forward(request, response);
} else {
response.sendRedirect("guess.do");
}
}
修改输入页面完成报错信息显示
<%@ page import="java.util.Map" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
<script>
function ff() {
let num1 = document.getElementById("num1").value;
let re = /^\d{1,18}$/;
let bb = re.test(num1);
if (!bb) {
alert("请输入合法的整型值");
}
return bb;
}
</script>
<%!
private String getError(HttpServletRequest request,String key) {
String msg = "";
Object obj=request.getAttribute("error");
if(obj!=null && obj instanceof Map){
Map<String,String> map=(Map<String,String>)obj;
if(map.containsKey(key))
msg=map.get(key);
}
return msg;
}
%>
</head>
<body>
<%=session.getAttribute("target")%>
<div>
<%
Object obj=session.getAttribute("history");
if(obj!=null && obj instanceof List){
List<Integer> list=(List<Integer>)obj;
for(Integer temp:list)
out.println(temp);
}
%>
</div>
<div id="div1"><%=request.getAttribute("msg")!=null?request.getAttribute("msg"):""%></div>
<form action="guess.do" method="post" οnsubmit="return ff();">
<input name="num" id="num1"/><span id="span1"><%=this.getError(request,"num")%></span><br/>
<input type="submit" value="验证"/>
</form>
</body>
</html>
比较笨的方式
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Random r=new Random();
int target=r.nextInt(900)+100;
request.setAttribute("target",target);
request.getRequestDispatcher("input.jsp").forward(request,response);
}
input.jsp显示一个表单,要求用户输入数据
<form action="guess.do" method="post">
<input type="hidden" name="target" value="<%=request.getAttribute("target")%>"/>
<input name="num"/><input type="submit" value="验证"/>
</form>
典型案例:购物车
pageContext
代表当前JSP页面的运行环境的对象;pageContext对象提供了对JSP页面内所有的对象及名字空间的访问,也就是说他可以访问到本页所在的SESSION,也可以取本页面所在的application的某一属性值,他相当于页面中所有功能的集大成者,它的本类名也叫pageContext
可以通过他获取其他八大隐式对象,例如:pageContext.getPage() ;
<%
JspWriter out1=pageContext.getOut();
ServletRequest request1=pageContext.getRequest();
ServletResponse response1=pageContext.getResponse();
HttpSession session1=pageContext.getSession();
ServletContext application1=pageContext.getServletContext();
Object page1=pageContext.getPage();
ServletConfig config1=pageContext.getServletConfig();
Exception exception1=pageContext.getException();
%>
pageContext 是一个域对象page,有生命周期:当访问JSP开始时创建pageConext对象,当访问JSP结束时销毁pageContext对象
作用范围:整个JSP页面
主要功能:在整个JSP页面中实现数据的共享
方法:
setAttribute(String name,Object value) ; //添加一个相应的域属性,
例如:request.setAttribute(“names”,names); //向request域中添加一个属性
getAttribute(String name) ;
removeAttribute(String name);//删除该属性
请求转发
pageContext.forward(“abc.jsp”);
- pageContext.forward(“bbb.jsp?id=123”);
- request.getRequestDispatcher(“bbb.jsp?id=123”).forward(request, response);
页面跳转
jsp页面跳转
不传递数据 get请求
<a href="bb.do">bb</a>
传递数据 get请求
<a href="bb.do?id=123">bb</a>
<form action="bb.do"> form表单默认提交方式为get
<input type="submit" value="提交数据" />
</form>
post请求
<form action="bb.do" method="post">
<input type="submit" value="提交数据" />
</form>
Servlet页面跳转
request.getRequestDispatcher("aa.jsp").forward(request,response); //请求转发
//客户端不参与; 当前Servlet和目标地址共享request
response.sendRedirect("aa.jsp");//重定向
//客户端参与; 当前Servlet不共享request
跟踪用户的4大方法
隐藏域
<form action="dd.do">
<input type="hidden" name="id" value="11"/>
URL重写
http://localhost:8080/dd.do?id=11
Cookie
用于实现客户端跟踪用户
在Servlet中,如果Cookie cookie = new Cookie(name,value) 调用Cookie对象的构造函数可以创建Cookie。Cookie对象的构造函数有两个字符串参数:Cookie名字和Cookie值。
名字和值都不能包含空格以及下列字符:[ ] ( ) = , " / ? @ : ;。
Cookie可以分为内存Cookie和文件Cookie。
-
只是进行了new操作的话,当用户退出Browser时,cookie会被删除掉,而不会被存储在客户端的硬盘上
-
如果要存储cookie,需加cookie.setMaxAge(200)。Cookie设置的生命周期单位是秒
然后需要使用response.addCooie(cookie)将cookie插入到一个Set-Cookie的HTTP请求报头中
由于浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB,因此Cookie不会塞满硬盘,更不会被用作“拒绝服务”攻击手段。
session的具体实现实际上依赖的就是内存Cookie
<%
Enumeration<String> names=request.getHeaderNames();
while(names.hasMoreElements()){
String name=names.nextElement();
String value=request.getHeader(name);
out.println(name+"--->"+value+"<br/>");
}
%>
<%=session.getId()%>
显示内容中注意:
cookie--->JSESSIONID=B7F7F449BB653EC538E753F37513F785
用户打开页面显示上次访问时间,一年内有效
存储文件cookie
<%
Date now=new Date();
DateFormat df=new SimpleDateFormat("yyyy-MM-dd-hh:mm:ss");
Cookie ck=new Cookie("lasttime",df.format(now));
ck.setMaxAge(10); //设置最大存活周期,单位为秒
response.addCookie(ck);
%>
读取cookie
<%
Cookie[] cks=request.getCookies();//获取所有的cookie
for(Cookie temp:cks){
out.println(temp.getName()+"::::"+temp.getValue()+"<br/>");
}
%>
###Session
用于实现服务器端跟踪用户,但是需要客户端的内存Cookie的支持,每次提交时需要传递一个Session的编号,用于区分不同用户
用户提交数据的预处理
-
客户端验证
采用js实现
<script> function ff(){ let num1=document.getElementById("num1").value; let re=/^\d{1,18}$/; let bb=re.test(num1); if(!bb){ alert("请输入合法的整型值"); } return bb; } </script> <form action="guess.do" method="post" onsubmit="return ff();"> <input name="num" id="num1"/> <input type="submit" value="验证"/> </form>
优点:
- 是在客户端上执行,不会对服务器造成压力
- 不需要网络数据传输,效率高
缺点:
- 很容易被绕过,所以安全性低
-
服务器端验证
采用java实现,运行在服务器端,一般和客户端验证规则一致
优点:
- 不能绕过,所以安全性高
缺点:
- 是在服务端上执行,会对服务器造成压力
- 需要网络数据传输,验证效率低
-
业务验证
采用Java实现,运行在服务器端,一般执行一些和业务规则相关的验证,以保证数据安全可靠