后台(15)——JSP(1)

简介: 探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制Android多分...

探索Android软键盘的疑难杂症
深入探讨Android异步精髓Handler
详解Android主流框架不可或缺的基石
站在源码的肩膀上全解Scroller工作机制


Android多分辨率适配框架(1)— 核心基础
Android多分辨率适配框架(2)— 原理剖析
Android多分辨率适配框架(3)— 使用指南


自定义View系列教程00–推翻自己和过往,重学自定义View
自定义View系列教程01–常用工具介绍
自定义View系列教程02–onMeasure源码详尽分析
自定义View系列教程03–onLayout源码详尽分析
自定义View系列教程04–Draw源码分析及其实践
自定义View系列教程05–示例分析
自定义View系列教程06–详解View的Touch事件处理
自定义View系列教程07–详解ViewGroup分发Touch事件
自定义View系列教程08–滑动冲突的产生及其处理


版权声明


JSP简介

Java Server Pages简称JSP,它和Servle一样也是SUN公司定义的一种用于开发动态web资源的技术。JSP的最大的特点在于:写JSP代码就像在写HTML但与HTML只能提供静态数据不同JSP允许开发人员在页面中嵌套java代码从而为用户提供动态数据。所以,可以形象的理解为:JSP = HTML + java


JSP之Hello World

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试</title>
<style type="text/css">
P {
    font-size: 35px;
    font-family: 宋体;
    color: red;
    background-color: pink;
}
</style>
</head>
<body>
    <p>原创作者:谷哥的小弟</p>
    <p>博客地址:http://blog.csdn.net/lfdfhl</p>
    <%
      Date date=new Date();
      out.println(date.toLocaleString());
    %>
</body>
</html>

运行后如下图所示:

这里写图片描述

哇哈,看到了吧:我们在该index.jsp文件中简单地写了两行java代码,部署应用后浏览器中显示了java代码的运行结果。

看到这我们心里可能就有疑惑了:

  • 浏览器访问JSP页面时Web服务器如何调用并执行一个jsp页面?
  • Web服务器在执行jsp页面时如何把jsp页面中的html标签发送到客户端?
  • Web服务器如何执行jsp页面中的java代码?

嗯哼,带着这些疑问,我们继续学习。


JSP原理

其实,jsp之所以可以被web服务器执行并返回给客户端,这是因为jsp从本质上来讲它就是一个Servlet。何出此言呢?我们打开刚才项目在Tomcat的work文件夹,查看其运行后生成的文件,请看下图:

这里写图片描述

嗯哼,瞅见了没?依据原来的index.jsp文件生成了对应的index_class.java和index_jsp.class。再打开index_class.java瞅瞅:

public final class index_jsp
extends 
org.apache.jasper.runtime.HttpJspBase 
implements 
org.apache.jasper.runtime.JspSourceDependent{ 

}

index_jsp继承自org.apache.jasper.runtime.HttpJspBase,那我们就继续来看看这个类:

public abstract class org.apache.jasper.runtime.HttpJspBase 
extends 
javax.servlet.http.HttpServlet 
implements 
javax.servlet.jsp.HttpJspPage {

}

嘿嘿,这个HttpJspBase又继承自HttpServlet。到了这里我们就明白了:jsp文件先会被翻译(转义)成一个HttpServlet子类的java文件再被编译成class文件;至此,jsp文件也就演变成了Servlet。

为了理解jsp的原理,我们来看看HttpJspBase的源码:

public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {

    private static final long serialVersionUID = 1L;

    protected HttpJspBase() {
    }

    @Override
    public final void init(ServletConfig config) 
        throws ServletException 
    {
        super.init(config);
        jspInit();
        _jspInit();
    }

    @Override
    public String getServletInfo() {
        return Localizer.getMessage("jsp.engine.info");
    }

    @Override
    public final void destroy() {
        jspDestroy();
        _jspDestroy();
    }

    /**
     * Entry point into service.
     */
    @Override
    public final void service(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException 
    {
        _jspService(request, response);
    }

    @Override
    public void jspInit() {
    }

    public void _jspInit() {
    }

    @Override
    public void jspDestroy() {
    }

    protected void _jspDestroy() {
    }

    @Override
    public abstract void _jspService(HttpServletRequest request, 
                                     HttpServletResponse response) 
        throws ServletException, IOException;
}

源码解析如下:

  • 在HttpServlet的init( )中执行_jspInit( ),请参见代码第9-15行
  • 在HttpServlet的destroy( )中执行_jspDestroy( ),请参见代码第23-26行
  • 在HttpServlet的service( )中执行_jspService( ),请参见代码第32-36行

小结:在HttpJspBase的生命周期方法中会执行jsp相关的生命周期方法

继续看index_jsp.java的代码:

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

  private javax.el.ExpressionFactory _el_expressionfactory;
  private org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    return _jspx_dependants;
  }

  public void _jspInit() {
    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
  }

  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=UTF-8");
      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("<html>\r\n");
      out.write("<head>\r\n");
      out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
      out.write("<title>测试</title>\r\n");
      out.write("<style type=\"text/css\">\r\n");
      out.write("P {\r\n");
      out.write("\tfont-size: 35px;\r\n");
      out.write("\tfont-family: 宋体;\r\n");
      out.write("\tcolor: red;\r\n");
      out.write("\tbackground-color: pink;\r\n");
      out.write("}\r\n");
      out.write("</style>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("\t<p>原创作者:谷哥的小弟</p>\r\n");
      out.write("\t<p>博客地址:http://blog.csdn.net/lfdfhl</p>\r\n");
      out.write("\t");

      Date date=new Date();
      out.println(date.toLocaleString());

      out.write("\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 { 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);
    }
  }
}

代码解析如下:

  • index_jsp.java实现了_jspInit( ),请参见代码第16-19行
  • index_jsp.java实现了_jspDestroy( ),请参见代码第21-22行
  • index_jsp.java实现了_jspService( ),请参见代码第24-84行
    在该方法中提供给了jsp几个非常重要的变量比如:HttpSession、ServletContext、ServletConfig、JspWriter、PageContext等等;它们都叫做JSP的内置对象。看到这我们也发现了:在_jspService( )中JspWriter将原本jsp文件中的标签原封不动地输出到了客户端!这也就是说服务端不会解析和处理原本jsp文件中的标签而是交给了客户端处理。

关于JSP的常用内置对象总结如下:

这里写图片描述

请注意:pageContext本身是一个域对象,但是它可操作其它三个域对象即request、session、application,例如它的如下方法:

setAttribute(String name,Object o,int scope);

getAttribute(String name,int scope);

removeAttribute(String name,int scope);

在这些方法中利用scope指定了操作的范围,其值可取为PageContext.PAGE_SCOPE 、PageContext.REQUEST_SCOPE 、PageContext.SESSION_SCOPE 、PageContext.APPLICATION_SCOPE

pageContext还有一个很强大的方法——findAttribute( ),它会自动依次从page、request、session、application中查找值,找到后就取出值并结束查找。

小结四个域对象:

PageContext、ServletRequest、HttpSession、ServletContext

PageContext : 它所存放的数据在当前页面有效,开发时使用较少
ServletRequest: 它所存放的数据在一次请求(转发)内有效
HttpSession: 它存放的数据在一次会话中有效,使用较多
ServletContext: 它所存放的数据在整个应用范围内都有效,但是因为其有效范围太大不利于数据隔离,应尽量少用


JSP最佳实践

我们知道:从本质上来讲,jsp就是一个Servlet。所以,JSP和Servlet都可以用于开发动态web资源。可是,如果让JSP既用java代码产生动态数据又做页面美化会导致代码难以维护;同理,如果让Servlet既处理逻辑又负责html的显示会导致程序代码可读性非常差。鉴于它们各自的特点,在长期的软件实践中,人们逐渐把Servlet作为web应用中的控制器组件来使用而把JSP作为数据显示模板来使用。

小结:

  • Servlet负责业务逻辑,即:获取表单数据、处理业务逻辑、分发与重定向

  • JSP负责数据的显示

请看如下示例:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>请您登陆</title>
</head>
<body>
    <%
        String msg = (String) request.getAttribute("msg");
        if (msg != null){
            out.print(msg);
        }
    %>
    <form action="/TestJSP01/testjsp" method="post">
        <br/>
        用 户:<input type="text" name="username"/>
             <br/><br/>
        密 码:<input type="password" name="password"/>
             <br/><br/>
             <input type="submit" value="登录"/>
    </form>
</body>
</html>

先写一个login.jsp,表单提交至如下Servlet

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

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

public class DoLoginServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if ("xzmly".equals(username) && "9527".equals(password)) {
            request.getSession().setAttribute("name", username);
            request.setAttribute("msg", "成功登录");
            response.sendRedirect(request.getContextPath()+"/success.jsp");
        } else {
            request.setAttribute("msg", "用户名或密码不正确,请重新登录");
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }
}

在该Servlet中获取表单提交的数据并处理。如果未通过验证则请求转发至login.jsp,如果通过验证则跳转到如下success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Welcome</title>
</head>
<body>
    欢迎您:<%
        String name = (String)session.getAttribute("name");
        out.print(name);
     %>

</body>
</html>

这个例子很简单,但是体现了Servlet与JSP的分工及协作,比如数据的传递和页面的跳转。

相关文章
|
7月前
|
Java
新闻发布项目——后台JSP界面adminManage/addNews.jsp
新闻发布项目——后台JSP界面adminManage/addNews.jsp
|
7月前
|
Java
新闻发布项目——后台JSP界面adminManage/editNews.jsp
新闻发布项目——后台JSP界面adminManage/editNews.jsp
|
7月前
|
Java
新闻发布项目——后台JSP界面adminManage/manageTopic.jsp
新闻发布项目——后台JSP界面adminManage/manageTopic.jsp
|
7月前
|
Java
新闻发布项目——后台JSP界面adminManage/modifyCategory.jsp
新闻发布项目——后台JSP界面adminManage/modifyCategory.jsp
|
7月前
|
Java 数据库 数据安全/隐私保护
基于SSM框架实现管科类考研自我管理系统(分前后台spring+springmvc+mybatis+maven+jsp+jquery)
基于SSM框架实现管科类考研自我管理系统(分前后台spring+springmvc+mybatis+maven+jsp+jquery)
|
7月前
|
Java
新闻发布项目——后台JSP界面adminManage/newsPage.jsp
新闻发布项目——后台JSP界面adminManage/newsPage.jsp
|
7月前
|
Java
新闻发布项目——后台JSP界面adminManage/addCategory.jsp
新闻发布项目——后台JSP界面adminManage/addCategory.jsp
|
7月前
|
Java
新闻发布项目——后台JSP界面adminManage/modifyNews.jsp
新闻发布项目——后台JSP界面adminManage/modifyNews.jsp
|
7月前
|
Java
新闻发布项目——后台JSP界面adminManage/adminIndex.jsp
新闻发布项目——后台JSP界面adminManage/adminIndex.jsp
|
7月前
|
Java
新闻发布项目——后台JSP界面adminManage/readNews.jsp
新闻发布项目——后台JSP界面adminManage/readNews.jsp