一.什么是JSP?

JSP全称是Java Server Pages(Java服务器页面。),它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。
JSP这门技术的最大的特点在于,写jsp就像在写html,但它相比html而言,html只能为用户提供静态数据,而Jsp技术允许在页面中嵌套java代码,为用户提供动态数据。

二、JSP原理

2.1、Web服务器是如何调用并执行一个jsp页面的?

浏览器向服务器发请求,不管访问的是什么资源,其实都是在访问Servlet,所以当访问一个jsp页面时,其实也是在访问一个Servlet,服务器在执行jsp的时候,首先把jsp翻译成一个Servlet,所以我们访问jsp时,其实不是在访问jsp,而是在访问jsp翻译过后的那个Servlet。
当我们通过浏览器访问index.jsp时,服务器首先将index.jsp翻译成一个index_jsp.class。在Tomcat服务器的work\Catalina\localhost\项目名\org\apache\jsp目录下可以看到index_jsp.class的源代码文件index_jsp.java。
我们可以看到,index_jsp这个类是继承 org.apache.jasper.runtime.HttpJspBase这个类。
HttpJspBase类是继承HttpServlet的,所以HttpJspBase类是一个Servlet,而index_jsp又是继承HttpJspBase类的,所以index_jsp类也是一个Servlet,所以当浏览器访问服务器上的index.jsp页面时,其实就是在访问index_jsp这个Servlet,index_jsp这个Servlet使用_jspService这个方法处理请求。

2.2、Jsp页面中的html排版标签是如何被发送到客户端的?

out.write('\r');
        out.write('\n');
  
  String path = request.getContextPath();
  String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
  
        out.write("\r\n");
        out.write("\r\n");
        out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
       out.write("<html>\r\n");
       out.write("  <head>\r\n");
       out.write("    <base href=\"");
       out.print(basePath);
       out.write("\">\r\n");
       out.write("    \r\n");
       out.write("    <title>First Jsp</title>\r\n");
       out.write("\t\r\n");
       out.write("  </head>\r\n");
       out.write("  \r\n");
       out.write("  <body>\r\n");
       out.write("    ");
 
         out.print("Hello Jsp");
     
       out.write("\r\n");
       out.write("  </body>\r\n");
       out.write("</html>\r\n");

在jsp中编写的java代码和html代码都会被翻译到_jspService方法中去,在jsp中编写的java代码会原封不动地翻译成java代码,如<%out.print(“Hello Jsp”);%>直接翻译成out.print(“Hello Jsp”);,而HTML代码则会翻译成使用out.write("<html标签>\r\n");的形式输出到浏览器。在jsp页面中编写的html排版标签都是以out.write("<html标签>\r\n");的形式输出到浏览器,浏览器拿到html代码后才能够解析执行html代码。

2.3、Web服务器在调用jsp时,会给jsp提供一些什么java对象?

jsp标签 调用 Java方法_java

三、JSP基础语法

3.1JSP表达式

JSP脚本表达式(expression)用于将程序数据输出到客户端
  语法:<%= 变量或表达式 %>

<%= new java.util.Date() %>

JSP引擎在翻译脚本表达式时,会将程序数据转成字符串,然后在相应位置用out.print(…) 将数据输给客户端。
JSP脚本表达式中的变量或表达式后面不能有分号(;)。

3.2JSP脚本片断

JSP脚本片断(scriptlet)用于在JSP页面中编写多行Java代码。语法:
    <%
    多行java代码
    %>

在<% %>中可以定义变量、编写语句,不能定义方法。

<%
     int sum=0;//声明变量
 
     /*编写语句*/
     for (int i=1;i<=100;i++){
         sum+=i;
     }
     out.println("<h1>Sum="+sum+"</h1>");
 %>

多个脚本片断中的代码可以相互访问,犹如将所有的代码放在一对<%%>之中的情况。如:out.println(x);
单个脚本片断中的Java语句可以是不完整的,但是,多个脚本片断组合后的结果必须是完整的Java语句,例如:

<%
     for (int i=1; i<5; i++) 
     {
 %>
     <H1>http://localhost:8080/JavaWeb_Jsp_Study_20140603/</H1>
 <%
     }
 %>

3.3JSP注释

在JSP中,注释有两大类:

显式注释:直接使用HTML风格的注释:<!- - 注释内容- ->

隐式注释:直接使用JAVA的注释://、/……/

JSP自己的注释:<%- - 注释内容- -%>

<!--这个注释可以看见-->
  
  <%
      //JAVA中的单行注释
  
      /*
          JAVA中的多行注释
      */
  %>
 
 <%--JSP自己的注释--%>

HTML的注释在浏览器中查看源文件的时候是可以看得到的,而JAVA注释和JSP注释在浏览器中查看源文件时是看不到注释的内容的,这就是这三种注释的区别。

四、JSP指令

JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。

  • page指令
  • Include指令
  • 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"%>

4.1Page指令

page指令用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它作用的都是整个JSP页面,为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置。
JSP 定义的page指令的完整语法:

<%@ page 
      [ language="java" ] 
      [ extends="package.class" ] 
      [ import="{package.class | package.*}, ..." ] 
      [ session="true | false" ] 
      [ buffer="none | 8kb | sizekb" ] 
      [ autoFlush="true | false" ] 
     [ isThreadSafe="true | false" ] 
      [ info="text" ] 
     [ errorPage="relative_url" ] 
     [ isErrorPage="true | false" ] 
     [ contentType="mimeType [ ;charset=characterSet ]" | "text/html ; charset=ISO-8859-1" ] 
     [ pageEncoding="characterSet | ISO-8859-1" ] 
     [ isELIgnored="true | false" ] 
 %>

page指令的import属性
在Jsp页面中,Jsp引擎会自动导入下面的包

java.lang.*
javax.servlet.*
javax.servlet.jsp.*
javax.servlet.http.*
可以在一条page指令的import属性中引入多个类或包,其中的每个包或类之间使用逗号(,)分隔.

<%@ page import="java.util.*,java.io.*,java.sql.*"%>

page指令的errorPage属性
errorPage属性的设置值必须使用相对路径,如果以“/”开头,表示相对于当前Web应用程序的根目录(注意不是站点根目录),否则,表示相对于当前页面
可以在web.xml文件中使用元素为整个Web应用程序设置错误处理页面。
元素有3个子元素,、、
子元素指定错误的状态码,例如:404
子元素指定异常类的完全限定名,例如:java.lang.ArithmeticException
子元素指定以“/”开头的错误处理页面的路径,例如:/ErrorPage/404Error.jsp
如果设置了某个JSP页面的errorPage属性,那么在web.xml文件中设置的错误处理将不对该页面起作用。

<%@ page language="java" import="java.util.*" errorPage="/ErrorPage/error.jsp" pageEncoding="UTF-8"%>
  <html>
    <head>
      <title>测试page指令的errorPage属性</title>
    </head>
    <body>
      <%
        //这行代码肯定会出错,因为除数是0,一运行就会抛出异常
          int x = 1/0;
    %>
   </body>
 </html>

在Test.jsp中,page指令的errorPage属性指明了出错后跳转到"/ErrorPage/error.jsp",error.jsp页面代码如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <html>
   <head>
     <title>错误信息友好提示页面</title>
   </head>
   <body>
            对不起,出错了!
   </body>
 </html>

五、include指令

在JSP中对于包含有两种语句形式:

1.@include指令
2.jsp:include指令
@include指令
@include可以包含任意的文件,当然,只是把文件的内容包含进来。

include指令用于引入其它JSP页面,如果使用include指令引入了其它JSP页面,那么JSP引擎将把这两个JSP翻译成一个servlet。所以include指令引入通常也称之为静态引入。

语法:<%@ include file=“relativeURL”%>,其中的file属性用于指定被引入文件的路径。路径以“/”开头,表示代表当前web应用。

include指令细节注意问题:

1.被引入的文件必须遵循JSP语法。
2.被引入的文件可以使用任意的扩展名,即使其扩展名是html,JSP引擎也会按照处理jsp页面的方式处理它里面的内容,为了见明知意,JSP规范建议使用.jspf(JSP fragments(片段))作为静态引入文件的扩展名。
3.由于使用include指令将会涉及到2个JSP页面,并会把2个JSP翻译成一个servlet,所以这2个JSP页面的指令不能冲突(除了pageEncoding和导包除外)。

六、JSP属性范围

  • page属性范围(pageContext)
      page属性范围相对好理解一些:在一个页面设置的属性,跳转到其他页面就无法访问了。但是在使用page属性范围的时候必须注意的是,虽然习惯上将页面范围的属性称为page范围,但是实际上操作的时候是使用pageContext内置对象完成的。
  • request属性范围
      request属性范围表示在一次服务器跳转中有效,只要是服务器跳转,则设置的request属性可以一直传递下去。
  • session属性范围
      session设置的属性不管如何跳转,都可以取得的。当然,session只针对一个用户 在第一个页面上设置的属性,跳转(服务器跳转/客户端跳转)到其他页面之后,其他的页面依然可以取得第一个页面上设置的属性。
  • application属性范围
      因为application属性范围是在服务器上设置的一个属性,所以一旦设置之后任何用户都可以浏览到此属性。

jsp四种属性范围的使用场合
  1、request:如果客户向服务器发请求,产生的数据,用户看完就没用了,像这样的数据就存在request域,像新闻数据,属于用户看完就没用的。
  2、session:如果客户向服务器发请求,产生的数据,用户用完了等一会儿还有用,像这样的数据就存在session域中,像购物数据,用户需要看到自己购物信息,并且等一会儿,还要用这个购物数据结帐。
  3、application(servletContext):如果客户向服务器发请求,产生的数据,用户用完了,还要给其它用户用,像这样的数据就存在application(servletContext)域中,像聊天数据。

七、JSP标签

JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护。

JSP常用标签
  jsp的常用标签有以下三个
jsp:include标签
jsp:forward标签
jsp:param标签

jsp:include标签
  jsp:include标签用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中,这种在JSP页面执行时的引入方式称之为动态引入。
语法:
<jsp:include page=“relativeURL | <%=expression%>” flush=“true|false” />
  page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得。
  flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输出的内容刷新到客户端。
jsp:forward标签
  jsp:forward标签用于把请求转发给另外一个资源。
  语法:
  <jsp:forward page=“relativeURL | <%=expression%>” />
  page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。
  
jsp:param标签
  当使用jsp:include和jsp:forward标签引入或将请求转发给其它资源时,可以使用jsp:param标签向这个资源传递参数。
  语法1:
<jsp:include page=“relativeURL | <%=expression%>”>
<jsp:param name=“parameterName” value=“parameterValue|<%= expression %>” />
</jsp:include>
  语法2:
<jsp:forward page=“relativeURL | <%=expression%>”>
<jsp:param name=“parameterName” value=“parameterValue|<%= expression %>” />
</jsp:include>
  jsp:param标签的name属性用于指定参数名,value属性用于指定参数值。在jsp:include和jsp:forward标签中可以使用多个jsp:param标签来传递多个参数。

代码示例:
dao层

/dao包一般用来存放操作数据库的对象类;

import com.kuang.pojo.News;

import java.util.List;

public interface NewsDao {
    //获得所有的新闻
    public List<News> getAllNews();

}
//NewsDao的实现类
public class NewsDaoImpl implements NewsDao {
    @Override
    public List<News> getAllNews() {
        List<News> list = NewsDB.list;
        return list;
    }

}

db层

import java.util.ArrayList;
import java.util.List;

public class NewsDB {

    public static List<News> list = new ArrayList<News>();

    static {
        list.add(new News("7.16","学习了JSP的使用以及源码分析"));
        list.add(new News("7.14","学习了Servlet,简单的JSP的使用"));
        list.add(new News("7.13","学习了Tomcat,Servlet的使用"));
        list.add(new News("7.13","学习了Tomcat,Servlet的使用"));
        list.add(new News("7.13","学习了Tomcat,Servlet的使用"));
        list.add(new News("7.13","学习了Tomcat,Servlet的使用"));
        list.add(new News("7.13","学习了Tomcat,Servlet的使用"));
        list.add(new News("7.13","学习了Tomcat,Servlet的使用"));
    }

}

pojo:

//实体类,一般放在pojo包下,【 or  entity  or JavaBeans】
//实体类,只有属性,一般用来映射数据库中的字段  ( O R M )
//私有属性 , 无参构造,有参构造
//get/set方法
//为了方便程序打印,建议加上toString();
public class News {

    private String data;
    private String content;

    public News() {
    }

    public News(String data, String content) {
        this.data = data;
        this.content = content;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "News{" +
                "data='" + data + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

service:

import java.util.List;

//service一般存放业务类
public interface NewsService {
    //获得所有的新闻
    public List<News> getAllNews();
}
import java.util.List;

public class NewsServiceImpl implements NewsService {

    //从dao层中取出相应的操作数据库的方法
    NewsDao newsDao = new NewsDaoImpl();

    @Override
    public List<News> getAllNews() {
        return newsDao.getAllNews();
    }
}

servlet:

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

public class NewsServlet extends HttpServlet {

    NewsService newsService = new NewsServiceImpl();

    @Test
    public void test(){


    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //写代码读取数据存到某个地方,让前端读取;

        List<News> allNews = newsService.getAllNews();//从业务层去获得数据中的全部新闻

        int i = 1;

        for (News allNew : allNews) { //遍历获得每一个新闻

            String data = allNew.getData();
            String content = allNew.getContent();

            //四大作用域
            //      page(不用它,代表当前页面)
            //      request(一次请求中有效): 登录注册
            //      session (一次会话中存在) : 购物车
            //      application:本质就是Context (全局,所有会话共享) : 广告
            //这四个作用域用来存放一些内容或者对象
            HttpSession session = req.getSession();

            session.setAttribute("data"+i,data);
            session.setAttribute("content"+i,content);

            System.out.println(session.getAttribute("data"+i));
            System.out.println(session.getAttribute("content"+i));

            i++;//自增
        }




        //数据都读取出来了,给你放到session中了,该去访问页面了
        resp.sendRedirect("index.jsp");


    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}