Web开发(二)--JSP

来源:互联网 发布:上海婚纱摄影推荐知乎 编辑:程序博客网 时间:2024/06/06 06:31

1、概述

Servlet中可以对用户的请求进行响应,可以向客户端返回信息。

在多数动态网页中,绝大部分内容都是固定不变的,只有局部内容需要动态产生和改变。

使用Servlet输出只有局部内容需要动态改变的网页,其所有静态内容也将由程序员用Java 程序代码产生,这样使得代码特别臃肿,编写和维护非常困难。

为了应对这样的状况,SUN公司在Servlet的基础上推出了Jsp技术:Java Server Pages

JSP是一种简化Servlet编写的技术,它将Java代码和HTML页面混合在同一个文件中编写,

只对网页中动态产生的部分采用Java代码编写,其他固定不变的部分使用HTML编写。

简单例子,在页面中显示当前时间:

<%@page import="java.util.Date"%><%@ page language="java" contentType="text/html; charset=ISO-8859-1"    pageEncoding="ISO-8859-1"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Insert title here</title></head><body><%Date date = new Date();%><p>Time Now:<%=date %></p></body></html>
页面显示:Time Now:Sat Apr 23 07:29:11 CST 2016

2、直观认识

1) JSP页面是由HTML语句和嵌套在其中的Java代码组成的一个普通文本文件,Jsp的文件扩展名必须为.jsp

2) Jsp页面中的Java代码需要嵌套在 <% 和 %> 之中,嵌套在 <% 和 %> 之中的Java 代码被称为脚本片断,没有嵌套在其中的的内容被称为jsp的模板元素

3) Java代码可以通过out.println()方法将Java 代码产生的结果字符串输出给客户端,out是Jsp的隐藏对象

4) Jsp文件同普通的HTML文件一样,可以放置在WEB应用程序除了WEB-INF及其子目录以外的其他任何目录中,访问方式同HTML文件的访问方式一样。

5) JSP表达式元素,只需将变量或者Java表达式封装在<%= 和 %>中,就可以向页面输出这个变量或者表达式的结果。

3、运行原理

JSP本质上是一个Servlet。
WEB容器接收到以.jsp为扩展名得到URL请求时,把JSP请求交给JSP引擎处理;
每个JSP页面在第一次被访问时,JSP引擎将它翻译成一个Servlet源程序,然后再编译成class文件;
然后由Servlet容器对待普通Servlet一样,装载和解释这个由JSP页面产生的Servlet;

概述中的时间的JSP页面,被翻译为java后的部分代码:
public final class helloworld_jsp extends org.apache.jasper.runtime.HttpJspBase    implements org.apache.jasper.runtime.JspSourceDependent {  public void _jspInit() {  }  public void _jspDestroy() {  }  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)        throws java.io.IOException, javax.servlet.ServletException {    final javax.servlet.jsp.PageContext pageContext;    javax.servlet.http.HttpSession session = null;    final javax.servlet.ServletContext application;    final javax.servlet.ServletConfig config;    javax.servlet.jsp.JspWriter out = null;    final java.lang.Object page = this;    javax.servlet.jsp.JspWriter _jspx_out = null;    javax.servlet.jsp.PageContext _jspx_page_context = null;    try {      response.setContentType("text/html; charset=ISO-8859-1");      pageContext = _jspxFactory.getPageContext(this, request, response,      null, true, 8192, true);      _jspx_page_context = pageContext;      application = pageContext.getServletContext();      config = pageContext.getServletConfig();      session = pageContext.getSession();      out = pageContext.getOut();      _jspx_out = out;      out.write("\r\n");      out.write("\r\n");      out.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");      out.write("<html>\r\n");      out.write("<head>\r\n");      out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">\r\n");      out.write("<title>Insert title here</title>\r\n");      out.write("</head>\r\n");      out.write("<body>\r\n");      out.write("\t");Date date = new Date();System.out.println(date);      out.write("\r\n");      out.write("\t<p>Time Now:");      out.print(date );      out.write("</p>\r\n");      out.write("</body>\r\n");      out.write("</html>");    } catch (java.lang.Throwable t) {      if (!(t instanceof javax.servlet.jsp.SkipPageException)){        out = _jspx_out;        if (out != null && out.getBufferSize() != 0)          try {            if (response.isCommitted()) {              out.flush();            } else {              out.clearBuffer();            }          } catch (java.io.IOException e) {}        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);        else throw new ServletException(t);      }    } finally {      _jspxFactory.releasePageContext(_jspx_page_context);    }  }}
可以看出,JSP页面被jsp引擎翻译为Servlet代码,jsp页面中的HTML元素都是通过out.println()的方法输出给页面,这个过程全部由JSP引擎完成,不需要程序员手动输出。
helloworld_jsp的类继承了HttpJspBase抽象类,HttpJspBase抽象类继承HttpServlet类,实现了HttpJspPage接口,其中_jspService()为抽象方法,被继承的类实现。
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {

4、隐含对象

在helloworld例子中,写在JSP页面中<% %>的代码,在被JSP引擎翻译后,是写在_jspService()方法中的,可以看上边_jspHelloWorld.java的代码。
在_jspService()方法中,两个形参变量:
① HttpServletRequest request、
② HttpServletResponse response,在Jsp页面中几乎不会调用response的任何方法;
以及方法中声明的六个变量:
③ PageContext pageContext,页面的上下文,可以从该对象获取到其他8个隐含对象,也可以获取到当前页面的其他信息,该对象就是代表当前页面(在自定义标签时经常使用)
④ HttpSession session,代表浏览器和服务器之间的一次对话
⑤ ServletContext application,代表当我WEB应用
⑥ ServletConfig config,(开发的时候几乎不使用)可以为Jsp页面在配置文件中配置Servlet,以及初始化参数。
⑦ JSPWriter out,调用out.println()方法,可以直接将信息打印到客户端的页面上。
⑧ Object page (this),指当前jsp页面的Servlet对象的引用,但为Object类型,几乎不使用。
⑨ 另外,还有一个exception。在声明了page指令的isErrorPage="true"时,才可以使用:<%@ page isErrorPage="true" %>
总共是九个隐含变量,这些变量可以在JSP页面的脚本片断里直接使用,无需声明,原因就是JSP引擎翻译后,是嵌入到_jspService()方法中的。

对属性的作用域的范围,从小到大:pageContext,request, session, application
1)位Jsp页面配置Servlet,使用jsp-file元素,匹配Servlet的名字与jsp文件
  <servlet>  <servlet-name>HelloJsp</servlet-name>  <jsp-file>/helloworld.jsp</jsp-file>  </servlet>  <servlet-mapping>  <servlet-name>HelloJsp</servlet-name>  <url-pattern>/Hellojsp</url-pattern>  </servlet-mapping>

5、JSP语法

1) 模板元素:不在<% 和 %>中的内容称为模板元素,基本为HTML语句。
注,在JSP编码格式为ISO-8859-1时,不可以写中文,可以在window->preferences->web->Jsp Files修改Encoding属性为UTF-8.
2) JSP表达式:<%= 和 %>之间,为Java表达式或者变量,可以直接将变量或者表达式的值输出到页面上。
    表达式被Jsp引擎翻译后的语句为:out.println(),也可以使用这个语句直接在Jsp页面输出。
3) Java 脚本片断是指嵌套在<% 和 %>中的Java代码,将被原封不动的搬移进由JSP页面所翻译成的Servlet的_jspServlet方法中,多个脚本片断可以相互进行访问。
4) JSP声明,如声明一个方法,不能写在<% 和 %>之中,因为_jspService()方法中,Java方法中不可以再声明方法。
    声明使用:<%! 和 %>之中嵌入声明,那么在翻译时,就会将声明放在_jspService()的外面。
   注意,这JSP页面中几乎从不这样使用。
5) 注释:格式<%-- 和 --%>之中,可以阻止Java代码的执行,注意JSP注释和HTML注释的区别
<%--<%Date date = new Date();%>--%>
注释只能放在 <% %>的外部,不能放在里边

6、属性相关

属性相关的方法:
Object getAttribute(String name) 获取指定属性
Enumeration getAttributeNames()  获取属性名字组成的Enumeration对象
void removeAttribute(String name) 移除指定属性
void setAttribute(String name, Object o) 设置属性

在四个域对象pageContext, request, session, application中,都有关于属性的这四个方法。

pageContext:属性的作用范围仅限于当前JSP页面
request:属性的作用范围仅限于同一个请求
session:属性的作为范围限于一次会话
application:属性的作用范围当前的WEB应用,是作用范围最大的,只要在一处设置属性,在其他的JSP和Servlet中都可以获取到。
使用方法:
<body><%pageContext.setAttribute("pageContextAttr", "pageContextValue");request.setAttribute("requestAttr", "requestValue");session.setAttribute("sessionAttr", "sessionValue");application.setAttribute("applicationAttr", "applicationValue");%>pageContextAttr:<%=pageContext.getAttribute("pageContextAttr")%><br><br>requestAttr:<%= request.getAttribute("requestAttr") %><br><br>sessionAttr:<%= session.getAttribute("sessionAttr") %><br><br>application:<%= application.getAttribute("applicationAttr") %></body>

输出结果:
pageContextAttr:pageContextValue

requestAttr:requestValue

sessionAttr:sessionValue

application:applicationValue 


属性范围结合重定向,可以有很大的作用。

7、请求的转发和重定向

客户端根据地址发送请求到服务器,如果服务器地址没有该请求的资源,那么服务器可以采用转发Forward和重定Redirect向两种方法,使请求获取到资源。
转发和重定向有本质的区别:转发,客户端只发送了一次请求;重定向,客户端发送了两次请求。
具体区别:
1)转发:地址栏是初次发出请求的地址
      重定向:地址栏不再是初次发出请求的地址,地址栏为最后响应的地址
2)转发:在最终的Servlet中,request对象和中转的那个request是同一对象
      重定向:request不是同一个对象
3)转发:只能转发给当前WEB应用下的资源
      重定向:可以重定向到任何资源
4)转发:/ 代表的是当前WEB应用的根目录
      重定向:/ 代表的是当前WEB站点的根目录,例如:http://localhost:8080/ 这就是WEB站点的根目录
转发,主要使用RequestDispatcher类的forward方法:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1.转发主要使用ReuqestDispather类,通过HttpServletRequest的getRequestDispatcher(String path)方法获取//2.然后调用RequestDispatcher的forward(request, response)方法实现转发System.out.println("ForwardServlet's doGet()方法");request.getRequestDispatcher("/testServlet").forward(request, response);}
重定向,直接使用response的sendRedirect方法:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//请求的重定向,直接调用response对象的sendRedirect(String location)方法//其中,location是重定向的地址,注意与转发中地址的区别,WEB应用内的不加/System.out.println("RedirectServlet's doGet()方法");response.sendRedirect("testServlet");}
其中,/testServlet映射TestServlet类:
@WebServlet("/testServlet")public class TestServlet extends HttpServlet {private static final long serialVersionUID = 1L;           public TestServlet() {        super();    }protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("TestServlet's doGet 方法");}}

8、JSP指令

JSP指令(directive)是为JSP引擎设计,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面的其余部分。
语法格式:<%@ 指令 属性名="值"%>
注意,属性名部分是大小写敏感的。
在目前JSP2.0中,定义了page,include,和taglib这三种指令。

page指令

page 指令用于定义JSP页面的各种属性,无论page 指令出现在JSP页面中的什么地方,它作用的都是JSP页面,
为了保持程序的可读性和遵循良好的编程规范,page指令最好是放在整个JSP页面的其实位置。
page指令常用的属性:
1)import属性,指定当前jsp页面对应的Servlet需要导入的类。<%@page import="java.util.Date"%>
2)session属性,取值为true或false,指定当前页面的session隐藏变量是否可用,也可以说访问当前页面时是否一定要产生HttpSession对象。<%@ page session="false" %>
3)errorPage和isErrorPage:
     ① errorPage 指定若当前页面出现错误的实际响应页面是什么,其中 / 表示的是当我WEB应用的根目录。
     例如:<%@ page errorPage="/error.jsp" %> 当页面出现错误时,利用请求转发机制,响应error.jsp页面给客户端
     ② isErrorPage 指定当前页面是否为错误处理页面,可以说明当前页面是否可以使用exception隐藏对象,需要指明的是,指定isErrorPage="true",并使用exception。
        注意,一般不建议直接访问该页面,isErrorPage为true 的页面用来接收别的页面产生的错误,并响应客户端。
                  在页面中出现错误,exception页面是直接崩溃的,exception对象无法用于获取本页面的错误信息。
     ③ 如何使客户不能直接访问一个页面呢?对于Tomcat服务器而言,WEB-INF下的文件是不能通过浏览器输入地址来访问的,但通过请求的转发是可以的。
4)contentType:指定当前JSP页面的响应类型,实际调用的是response.setContentType("")方法,通常情况下,对于Jsp页面其取值均为:text/html; charset=UTF-8
5) pageEncoding:指定当前JSP页面的字符编码,通常情况下该值与charset的值一致。
6)isELIgnore,指定当前JSP页面是否可以使用EL表达式,通常取值为true。
<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8" %><%@ page errorPage="/error.jsp" %><%@ page session="false" %><%@ page import="java.util.Date" %>

include指令

include指令用于通知JSP引擎在翻译当前JSP页面时,将其他文件中的内容合并到当前JSP页面转换成的Servlet源文件中,这种在源文件级别进行引入的方式称之为静态引入,
当前JSP页面与静态引入的页面紧密结合为一个Servlet。
语法:<%@ include file="relativeURL"%> 其中file属性用于指定被引入文件的相对路径。
相对路径:如果以 / 开头,表示相对于当前WEB应用程序的根目录(注意不是站点根目录),否则表示相对于当前文件。

9、配置文件中配置错误页面

可以在web.xml中直接配置错误文件error.jsp,在web-app标签下直接使用error-page标签,就不需要使用errorPage属性了。
  <error-page>  <error-code>500</error-code>  <location>/WEB-INF/error.jsp</location>  </error-page>
500 代表页面出错,404代表地址对应的资源未找到时,该响应哪个页面,通过error-page标签也可以设置。
  <error-page>  <error-code>404</error-code>  <location>/hello.jsp</location>  </error-page>
还可以根据错误的类别,配置响应页面:
<error-page><exception-type>java.lang.ArithmeticException</exception-type><location>/WEB-INF/error.jsp</location></error-page>

10、JSP标签

标签是指通过采用HTML标签语言,实现JSP的各种功能,有include 标签实现文件包含,forward标签实现请求转发等
语法格式:<jsp:标签 属性="值"></jsp:标签>

jsp:include标签:

语法:
<jsp:include page="hello.jsp"></jsp:include>
动态引入:并不像include指令生成一个Servlet源文件,include标签生成两个Servlet源文件,然后通过一个目标方法的方式把目标页面包含进来。
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "hello.jsp", out, false);
jsp文件翻译为Servlet后的java文件的地址在:eclipse工作空间\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\work\Catalina\localhost\项目名\org\apache\jsp 文件夹下。
include指令和jsp:include标签的主要区别:
<jsp:include>标签是在当前JSP页面的执行期间插入被引入资源的输出内容,被动态引入的资源必须是一个能独立被WEB容器调用和执行的资源;
include指令只能引入遵循JSP格式的文件,被引入文件和当前JSP文件共同被翻译成一个Servlet源文件。

jsp:forward标签:

语法:
<jsp:forward page="/helloworld.jsp"></jsp:forward>
相当于:
<%request.getRequestDispatcher("/helloworld.jsp").forward(request, response);%>
可以使用jsp:parm子标签向转发页面传递参数,同样,jsp:include也可以使用jsp:parm子标签
<jsp:forward page="helloworld.jsp"><jsp:param value="yuchen" name="username"/></jsp:forward>
可以在helloworld.jsp页面中获取这个参数:
<%= request.getParameter("username") %>
一般在jsp页面中实现包含和转发功能的时候,就直接使用jsp标签,这样不需要写java 代码,简化操作。

10、关于中文乱码

在开发过程中,经常会遇到中文乱码的问题,在JSP中,中文乱码主要在两个方面:页面的显示和参数的传递。
1)在JSP页面上输入中文,请求页面后不出现乱码:保证contentType="text/html;charset=UTF-8" 和pageEncoding="UTF-8" 的编码一致,且都支持中文,
      一般建议设为UTF-8,还需保证浏览器显示的字符编码与请求的JSP页面的编码一致。
2)获取中文参数:默认参数在传递中使用的编码格式为ISO-8859-1
① 对于POST请求方法,只需在获取参数之前调用request.setCharacterEncoding("UTF-8")即可
<% request.setCharacterEncoding("UTF-8"); %><%= request.getParameter("username") %>
② 对于GET方法,前面的方式对GET请求无效,可以通过修改servlet.xml配置文件的方式
修改tomcat服务器以及在eclipse映射文件servlet.xml的Connector节点,为该节点添加属性useBodyEncodingForURI="true"
    <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" useBodyEncodingForURI="true"/>
也可以通过对字符串进行重新编码的方式,构建新的字符串,但是这种方式比较麻烦,不建议使用,建议使用修改servlet.xml配置文件的方式。
<% String val = request.getParameter("username");String username = new String(val.getBytes("ISO-8859-1"),"UTF-8");out.print(username);%>








0 0