JSP
当客户端访问jsp页面的时候,服务器会先把jsp翻译成一个servlet,翻译成的servlet位于tomcat根目录下的work文件夹下 。可以查看源码看看。
jsp是HTTPServlet的孙子。
JSP模板更改
找到myeclipse的安装目录,搜索servlet,然后在查看servlet的具体路径
在该路径下有个jsp文件夹,修改里面的jsp.vt1
同时要把pageEncoding改为UTF-8
JSP指令:是为JSP引擎使用的,也就是给tomcat服务器使用的,是告诉服务器如何将jsp翻译成servlet,他们并直接的产生任何的可见输出,
JSP2.0规范中定义了三个指令:
1.page指令
2.include指令
3.taglib指令
JSP指令的基本语法格式:
<%@ 指令 属性名="值" %>
例如:<%@ page contentType="text/html;charset=gb2312"%>
如果一个指令有多个属性,这多个属性可以写在一个指令中,也可以分开写。
例如:
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.util.Date"%>
也可以写作:
<%@ page contentType="text/html;charset=gb2312" import="java.util.Date"%>
详情请参看jsp指令的完整语法。
jsp指令中可以把session设为false,这样jsp翻译成的servlet中就没有session对象了,在该jsp页面中就不能再使用session了。
因为session的声明周期相对较长,所以让开发者可以关闭session。
jsp解决中文乱码:jsp 中page指令的pageEncoding=“UTF-8”
include指令:主要用来做包含
include指令用于引入其它JSP页面,如果使用include指令引入了其它JSP页面,那么JSP引擎将把这两个JSP翻译成一个servlet。所以include指令引入通常也称之为静态引入。
语法:<%@ include file="relativeURL"%>
其中的file属性用于指定被引入文件的路径。路径以“/”开头,表示代表当前web应用。(/ 是给服务器用的,所以代表当前web应用)
include指令细节:
1. 被引入的文件必须遵循JSP语法。
2. 被引入的文件可以使用任意的扩展名,即使其扩展名是html,JSP引擎也会按照处理jsp页面的方式处理它里面的内容,为了见明知意,JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名。
3. 由于使用include指令将会涉及到2个JSP页面,并会把2个JSP翻译成一个servlet,所以这2个JSP页面的指令不能冲突(除了pageEncoding和导包除外)。
静态包含。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>include指令(静态包含(编译时包含),它包含的所有jsp会编译成一个servlet)</title> </head> <body> <%@include file="/public/head.jsp" %> aaaaaaaaaaaaaaaa<br/> <%@include file="/public/foot.jsp" %> </body> </html>
动态包含:服务器会把这三个jsp翻译成三个servlet,执行的时候再包含进来
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>动态包含(这种情况是运行时包含)</title> </head> <body> <% request.getRequestDispatcher("/public/head.jsp").include(request,response); %> <% response.getWriter().write("aaaaaaaaaaaaa<br/>"); %> <% request.getRequestDispatcher("/public/foot.jsp").include(request,response); %> </body> </html>
开发中推荐使用静态包含。
JSP运行原理
每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理。JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet) ,然后按照servlet的调用方式进行调用。
由于JSP第一次访问时会翻译成servlet,所以第一次访问通常会比较慢,但第二次访问,JSP引擎如果发现JSP没有变化,就不再翻译,而是直接调用,所以程序的执行效率不会受到影响。
JSP引擎在调用JSP对应的_jspServlet时,会传递或创建9个与web开发相关的对象供_jspServlet使用。JSP技术的设计者为便于开发人员在编写JSP页面时获得这些web对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这9大对象的引用。
九大隐式对象:
Request
Response
Session
application ----servletContext
config ----servletConfig
Page ----this
Exception
Out jspWriter:相对于一个带缓冲功能的printWriter
pageContext
out隐式对象:
1. out隐式对象用于向客户端发送文本数据。
2. out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似。
3. JSP页面中的out隐式对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。
只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
a. 设置page指令的buffer属性关闭了out对象的缓存功能
b. out对象的缓冲区已满
c. 整个JSP页面结束
同时使用out和response.getwriter()输出数据的问题:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>out隐式对象注意的问题</title> </head> <body><% out.write("hahhahahahah"); response.getWriter().write("wowowowo"); %> </body> </html>
程序会先输出wowowow,在输出hahahahah,因为out隐式对象有缓冲功能。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>out隐式对象注意的问题</title> </head> <body> aaaaaaaaaaa ----这个会调用隐式对象out输出 <% response.getWriter().write("wowowowo"); %> </body> </html>
输出的结果还是先输出wowowow,在输出aaaaaa
所以在jsp中建议只使用隐式对象输出,最好不要两个混用。
用JSP实现文件下载:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@page import="java.io.FileInputStream"%><% String path = application.getRealPath("/download/1.jpg"); //c:\\ String filename = path.substring(path.lastIndexOf("\\")+1); response.setHeader("content-disposition","attachment;filename=" + filename); FileInputStream in = new FileInputStream(path); byte buffer[] = new byte[1024]; int len = 0; while((len=in.read(buffer))>0){ response.getOutputStream().write(buffer,0,len); } in.close(); %>
注意:一定要保证jsp中不能有其他的代码,包括空格,因为jsp页面中的文本数据在翻译成的servlet会用out输出,out是一个字符流,getOutputStream是字节流,输出图片只能用字节流,在一个servlet中不允许同时用字节流和字符流输出,会抛异常。
pageContext对象
pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境,
1. 这个对象不仅封装了对其它8大隐式对象的引用。
2. 它自身还是一个域对象,可以用来保存数据。
3. 并且,这个对象还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其它资源、检索其它域对象中的属性等。
通过pageContext获得其他对象
pageContext获取八大隐式对象的方法一般用在自定义标签中,在jsp中可以直接获取八大隐式对象,不需要通过pageContext来获取。
自定义标签用来移除jsp中的java代码的。把pageContext传递过去,就可以在java类中获取八大隐式对象,这就是为什么pageContext中封装八大隐式对象的意义。
pageContext作为域对象 :
pageContext封装了访问其他域的方法,可以指定往哪个域中存数据,
<% pageContext.setAttribute("data","abc",PageContext.SESSION_SCOPE); %> <%=pageContext.getAttribute("data",PageContext.SESSION_SCOPE) %>
<% pageContext.findAttribute("data"); //page request session application 范围由小变大
%>
findAttribute("data"); 会先从page域中找,再从request域中找,还是找不到,会从session域中找,还找不到就从application域中找。
${data} 作用就是依次从四个域中找数据data,功能等效下面一句java代码。
<% pageContext.findAttribute("data");
%>
引入和跳转到其他资源 :
PageContext类中定义了一个forward方法和两个include方法来分别简化和替代RequestDispatcher.forward方法和include方法。
方法接收的资源如果以“/”开头, “/”代表当前web应用。
<% request.getRequestDispatcher("/index.jsp").forward(request,response); pageContext.forward("/index.jsp"); 这两个等效 pageContext.include("/public/head.jsp");动态包含
%>
JSP标签:避免在jsp中出现java代码
<jsp:include>标签
<jsp:forward>标签
<jsp:param>标签
映射JSP
<servlet>
<servlet-name>SimpleJspServlet</servlet-name>
<jsp-file>/jsp/simple.jsp</jsp-file>
<load-on-startup>1</load-on-startup >
</servlet>
……
<servlet-mapping>
<servlet-name>SimpleJspServlet</servlet-name>
<url-pattern>/xxx/yyy.html</url-pattern>
</servlet-mapping>
这时可以使用/jsp/simple.jsp访问,也可以使用/xxx/yyy.html访问,是一样的。
四个域对象:
pageContext(称之为page域) 页面范围
request(称之为request域)请求范围
session(称之为session域)会话范围
servletContext(称之为application域)应用程序范围,只要web程序不停,都有效