[JSP] 笔记

发布时间 2023-04-01 10:52:12作者: 李八御

JSP

java server pages java 服务端页面

jsp = java + html

为什么用JSP?

JSP 为动态页面而生,当页面需要展示动态的数据时,我们不可能像下图这样用 servlet 中的 write 写整个页面。那样太过繁琐和复杂。

img

JSP 的作用:简化开发,避免用 Servlet 输出 HTML 标签。

JSP 原理

img

JSP 本质上就是 Servlet

JSP在被访问时,由JSP容器(Tomcat)将其转换为Java文件(Servlet),再由JSP容器(Tomcat)将其编译,最终对外提供服务的其实就是这个字节码文件


JSP 脚本

<% %>

  • 在 _JspService() 方法中使用

<%= %>

  • 等价于 <% out.print() %>

<%! %>

  • 在 _JspService() 之外,直接被类包含,就是成员位置

举例

hello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Hello</title>
</head>
<body>
<h1>Hello Html!</h1>
<%!
    String username = "zhangsan";
    void showName() {
        System.out.println(username);
    }
%>

<%
    String str = "Hello Jsp~";
    out.print(str + "<br>");
    System.out.println(str);
    showName();
%>

<%="Hello out.print()" + str%>

</body>
</html>

生成的hello_jsp.java

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

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


    // 在 <%! %> 中编辑的内容作为成员变量
    String username = "zhangsan";
    void showName() {
        System.out.println(username);
    }

  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("\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("    <title>Hello</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("<h1>Hello Html!</h1>\r\n");
      out.write("\r\n");
      out.write("\r\n");

    String str = "Hello Jsp~";
    out.print(str + "<br>");
    System.out.println(str);
    showName();

      out.write("\r\n");
      out.write("\r\n");
      out.print("Hello out.print()" + str);
      out.write("\r\n");
      out.write("\r\n");
      out.write("</body>\r\n");
      out.write("</html>\r\n");
    } 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);
    }
  }
}

JSP 查询数据库并展示

<%@ page import="java.util.List" %>
<%@ page import="com.jsp.pojo.Hero" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="org.apache.ibatis.io.Resources" %>
<%@ page import="org.apache.ibatis.session.SqlSessionFactory" %>
<%@ page import="org.apache.ibatis.session.SqlSessionFactoryBuilder" %>
<%@ page import="org.apache.ibatis.session.SqlSession" %>
<%@ page import="com.jsp.mapper.HeroMapper" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();

    HeroMapper heroMapper = sqlSession.getMapper(HeroMapper.class);
    List<Hero> heroList = heroMapper.selectAll();
    sqlSession.close();
%>

<html>
<head>
    <title>Hero</title>

    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">

    <!-- 可选的 Bootstrap 主题文件(一般不用引入) -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">

    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
</head>
<body>
<div class="panel panel-default col-lg-4">
    <!-- Default panel contents -->
    <div class="panel-heading">英雄列表</div>

    <!-- Table -->
    <table class="table">
        <tr>
            <th>ID</th>
            <th>英雄</th>
            <th>生命</th>
            <th>伤害</th>
        </tr>

        <%
            for (Hero hero : heroList) {
                int id = hero.getId();
                String name = hero.getName();
                int hp = hero.getHp();
                float damage = hero.getDamage();
        %>

        <tr>
            <td><%=id%></td>
            <td><%=name%></td>
            <td><%=hp%></td>
            <td><%=damage%></td>
        </tr>

        <%
            }
        %>
    </table>
</div>
</body>
</html>

效果展示

img

JSP 脚本可以被截断

如下,将 for 循环截断,包含一段 <tr> 元素,这样会在页面自动遍历展示列表。

<%
    for (Hero hero : heroList) {
        int id = hero.getId();
        String name = hero.getName();
        int hp = hero.getHp();
        float damage = hero.getDamage();
%>

<tr>
    <td><%=id%></td>
    <td><%=name%></td>
    <td><%=hp%></td>
    <td><%=damage%></td>
</tr>

<%
    }
%>

JSP 的缺点

由于JSP页面内,既可以定义HTML标签,又可以定义Java代码,造成了以下问题:

  1. 书写麻烦:特别是复杂的页面
  2. 阅读麻烦
  3. 复杂度高:运行需要依赖于各种环境,JRE,JSP容器,JavaEE...
  4. 占内存和磁盘:JSP会自动生成.java和.class文件占磁盘,运行的是.class文件占内存
  5. 调试困难:出错后,需要找到自动生成的.java文件进行调试
  6. 不利于团队协作:前端人员不会Java,后端人员不精HTML 心

替代品:HTML + AJAX

img

综上,可见单独使用 JSP 技术会使页面臃肿不堪,难以阅读维护,无法分工合作。所以,应该采取 Servlet + JSP 的方式,尽量地让 Servlet 只做业务逻辑,让 JSP 只做数据展示。

所以,就需要 EL 表达式、JSTL 标签这两个技术。


EL 表达式

  • Expression Language表达式语言,用于简化JSP页面内的Java代码
  • 功能:获取数据
  • 语法:${expression}
    • ${username}:获取域中存储的 key 为username的数据值

JavaWeb 四大域对象:

域对象 生效位置
page 当前页面
request 当前请求
session 当前会话
application 当前应用

EL 表达式会从内向外寻找,直到找到数据为止。

img


JSTL 标签

依赖

<!--JSTL标签库-->
<dependency>
  <groupId>jstl</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>
<dependency>
  <groupId>taglibs</groupId>
  <artifactId>standard</artifactId>
  <version>1.1.2</version>
</dependency>

if 标签

<c:if test="${heroDamage > 500}">
    <h1>${heroName}伤害很高</h1>
</c:if>

img

for-each 标签

<c:forEach items="${heroList}" var="hero" varStatus="status">
    <tr>
        <%--<td>${hero.id}</td>--%>
        <td>${status.count}</td>
        <td>${hero.name}</td>
        <td>${hero.hp}</td>
        <td>${hero.damage}</td>
        <td>
            <c:if test="${hero.damage <= 800}">
                战士
            </c:if>
            <c:if test="${hero.damage > 800}">
                刺客
            </c:if>
        </td>
    </tr>
  </c:forEach>

varStatus 是遍历状态信息,有两个子项

  • index 从 0 开始
  • count 从 1 开始

普通 for 循环

<div>
    <c:forEach begin="0" end="10" step="1" var="num">
        <a href="#">${num}</a>
    </c:forEach>
</div>

效果:

img

分页条的原型。