JSP相关内容

14

现有问题

通过Servlet响应客户端页面,有什么缺点?

  • 显示代码麻烦。
  • 代码维护麻烦。

Servlet不适合展示复杂页面数据。

Servlet的作用:处理客户端请求,调用业务逻辑层,转发和重定向。

什么是JSP?

概念:

  • JSP全称:Java Server Page,Java服务器页面。
  • 和Servlet一样,是SUN公司定义的一种动态网页开发技术。

特点:

  • 基于HTML模版,可以在HTML模版嵌入Java代码和JSP标签。

作用:

  • 适用于复杂的页面显示。

JSP语法

JSP页面

  • 可以包含指令脚本脚本表达式声明静态内容等。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>jsp基本语法</title>
</head>
<body>
<h2>jsp基本语法</h2>
<ul>
    <li> 1.指令:page include taglib</li>
    <li> 2.脚本:java语句 局部变量
        <%
            System.out.println("jsp");
            String name = "lz";
            out.print(name);
        %>
    </li>
    <li> 3.脚本表达式:java代码 输出数据
        <%=name%>
    </li>
    <li> 4.声明:方法 成员变量
        <%!
            public String toUpperCase(String s) {
                return s.toUpperCase();
            }
        %>
        <%=toUpperCase(name)%>
    </li>
    <li> 5.静态内容 : html、css、js</li>
    <li> 6.JSP注释
        <%-- jsp注释(不显示,既可以注释html,又可以java) --%>
        <!-- html注释(显示)  -->
        <%--java中的注释 (不显示) 
                 单行注释//  多行注释 /**/
         --%>
    </li>
</ul>
</body>
</html>

JSP与Servlet

关系:

  • JSP文件在容器中会转换成Servlet。
  • JSP是对Servlet的一种高级封装。
  • 本质还是Servlet。

从源码角度解释:

运行tomcat,进入tomcat运行后的上述地址文件夹。其中文件有:

  • conf -> Catalina -> localhost中存放了虚拟路径的配置文件
  • logs 日志文件
  • work工作目录 -> Catalina -> localhost -> 项目目录 进入这个目录

打开jsp基本语法_jsp.java文件:

[wppay]

看到类的定义如下省略了类主体和两个实现,这里我们暂时不分析这个文件:

public final class JSP基本语法_jsp extends org.apache.jasper.runtime.HttpJspBase

在tomcat源码文件中找到HttpJspBase这个类,如下:

public abstract class HttpJspBase extends HttpServlet implements HttpJspPage 

可以看到我们写的页面继承了HttpJspBase,而HttpJspBase又继承了HttpServlet。

也就是说我们写的JSP就是Servlet。

好了,我们再回看jsp基本语法_jsp.java这个文件,文件内容如下,可以简单看下,后面会有分析。

public final class JSP基本语法_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {


            public String toUpperCase(String s) {
                return s.toUpperCase();
            }
        
  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 static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = null;
  }

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

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

  public java.util.Set<java.lang.String> getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    return _jspx_imports_classes;
  }

  public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
    if (_el_expressionfactory == null) {
      synchronized (this) {
        if (_el_expressionfactory == null) {
          _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
        }
      }
    }
    return _el_expressionfactory;
  }

  public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
    if (_jsp_instancemanager == null) {
      synchronized (this) {
        if (_jsp_instancemanager == null) {
          _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
        }
      }
    }
    return _jsp_instancemanager;
  }

  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 java.lang.String _jspx_method = request.getMethod();
    if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
      return;
    }

    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("    <title>jsp基本语法</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("<h2>jsp基本语法</h2>\r\n");
      out.write("<ul>\r\n");
      out.write("    <li> 指令:page include taglib</li>\r\n");
      out.write("    <li> 脚本:java语句 局部变量\r\n");
      out.write("        ");

            System.out.println("jsp");
            String name = "lz";
            out.print(name);
        
      out.write("\r\n");
      out.write("    </li>\r\n");
      out.write("    <li> 脚本表达式:java代码 输出数据\r\n");
      out.write("        ");
      out.print(name);
      out.write("\r\n");
      out.write("    </li>\r\n");
      out.write("    <li> 声明:方法 成员变量\r\n");
      out.write("        ");
      out.write("\r\n");
      out.write("        ");
      out.print(toUpperCase(name));
      out.write("\r\n");
      out.write("    </li>\r\n");
      out.write("    <li> 静态内容</li>\r\n");
      out.write("    <li>JSP注释\r\n");
      out.write("        ");
      out.write("\r\n");
      out.write("        <!-- html注释 -->\r\n");
      out.write("        ");
      out.write("\r\n");
      out.write("    </li>\r\n");
      out.write("</ul>\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 {
            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实现了不需要我们手动拼接前端页面,实现自动拼接out.write()。声明的方法、变量都可以在里面找到以java的形式。

这个JSP基本语法_jsp里面主要的方法是:

public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)

那_jspService这个方法有什么时候调用呢?回到我们的tomcat源码文件中的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", Constants.SPEC_VERSION);
    }

    @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;
}

其中_jspService是一个抽象方法

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

说明子类的_jspService把父类的_jspService进行了重写。又有下面的service方法:

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

可以看到service方法调用了抽象方法_jspService,但_jspService方法被子类JSP基本语法_jsp给重写了,实际调用的是子类JSP基本语法_jsp重写后的方法。

那 service 又是什么时候会被调用呢?被忘了HttpJspBase类继承了HttpServlet。

public abstract class HttpJspBase extends HttpServlet implements HttpJspPage

在被请求后会调用。(Servlet的生命周期)

再看两者的关系,就可以明白确实如此:

  • JSP文件在容器中会转换成Servlet。
  • JSP是对Servlet的一种高级封装。
  • 本质还是Servlet。

区别:

  • JSP可以很方便的编写或者修改HTML网页而不用去面对大量的println语句。

JSP实现原理

Tomcat里面有个JSP引擎会将xxx.jsp转换成Java代码,进而编译成.class文件运行,最终将运行结果通过response响应给客户端。

JSP指令

JSP指令用来设置与整个JSP页面相关的属性。

page指令

page指令:

  • 为容器提供当前页面的使用说明。一个JSP页面可以包含多个page指令。
  • 语法:<%@ page attribute1="value1" attribute2="value2" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="message.jsp"
         isErrorPage="true" session="false" pageEncoding="utf-8" buffer="8kb" %>
<html>
<head>
    <title>page指令</title>
</head>
<body>
<h2>page指令</h2>
<ul>
    <li>contentType:设置页面的MIME类型和字符编码格式</li>
    <li>language:页面的语言 默认java</li>
    <li>import:导入类</li>
    <li>errorPage:当页面发送错误时跳转的页面</li>
    <li>isErrorPage:指定当前页面是否可以作为另一个JSP页面的错误处理页面</li>
    <li>session:是否创建session对象,默认为true</li>
    <li>pageEncoding:指定jsp页面本身编码</li>
    <li>buffer:页面的缓冲区 默认8kb</li>
</ul>
<%
    ArrayList<Object> list = new ArrayList<>();
    //int i = 10 / 0;
%>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<head>
    <title>提示页面</title>
</head>
<body>
出现了错误.
<%-- isErrorPage="true" 不写下面的式子获取不到--%>
<%
    System.out.println(exception.getMessage());
%>
</body>
</html>

include指令

  • 通过include指令来包含其他文件。
  • 被包含的文件可以是JSP文件、HTML文件或文本文件。
  • 包含的文件就好像是当前JSP文件的一部分,会被同时编译执行。
  • include指令包含称为静态包含。
  • 包含的内容里面不要有<html>等标签直接是内容
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
    <title>指令include</title>
</head>
<body>
    <%@include file="header.jsp"%>

    <h3>include:实现静态包含,把另一个页面中的内容直接复制到当前页面</h3>

    <%@include file="footer.jsp"%>
</body>
</html>

header.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
    页面头部
</div>

footer.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
    页面尾部
</div>

对应的java代码如下:

taglib指令

  • 引入JSP的标准标签库。
  • 语法:<%@ taglib uri="外部标签库路径" prefix="前缀" %>

内置的动作标签

动作标签指的是JSP页面在运行期间执行的命令。

  • jsp:include:
    • 动作元素会将外部文件输出结果包含在JSP中。
    • 动作元素称为动态包含
<jsp:include page="header.jsp"></jsp:include>

注意:

  • include指令是将外部文件的输出代码复制到了当前JSP文件中。
  • 而jsp:include动作不同,是将外部文件的执行结果引入到了当前JSP文件中。

对应的java代码如下:

再从生成的文件来看,include指令不会生成header.jsp和footer.jsp文件,但是<jsp:include>会生成。

  • jsp:useBean:
    • 用来创建一个将在JSP页面中使用的JavaBean。

User类

public class User {
  private String name;
  private int age;
  ........
}

手工创建对象:

<%
    User user1 = new User("lz", 22);
%>

使用jsp:useBean:

<jsp:useBean id="user" class="com.qf.domain.User"></jsp:useBean>

输出:

<%=user.toString()%>

对应的java代码:

  • jsp:setProperty:
    • 在jsp:useBean元素之后使用jsp:setProperty进行属性的赋值。
<jsp:setProperty name="user" property="name" value="wl"></jsp:setProperty>
<jsp:setProperty name="user" property="age" value="20"></jsp:setProperty>

对应的java代码:

  • jsp:getProperty:
    • jsp:getProperty动作获取指定Bean属性的值,转换成字符串,然后输出。
<jsp:getProperty name="user" property="name"/>
  • jsp:forward:
    • jsp:forward动作把请求转到另外的页面。
  • jsp:param:
    • 在转发动作内部使用,做参数传递。
<%
    request.setCharacterEncoding("utf-8");
    //之前转发
    //request.getRequestDispatcher("/index.jsp").forward(request,reponse);
%>
<jsp:forward page="index.jsp">
    <jsp:param name="address" value="北京"/>
</jsp:forward>

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>首页</title>
</head>
<body>
首页
<%
    String address = request.getParameter("address");
    out.print(address);
%>
</body>
</html>

内置对象(重点)

JSP自动创建的对象,可以直接使用。

这九个对象在什么地方创建好的?可以看JSP与Servlet的关系我们找到了jsp转换成的java文件,其中这八个对象就定义在_jspService里面。

少了一个exception,将jsp代码修改如下运行tomcat重新找到那个文件就会找到:

<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>

out 对象

  • 页面中输出内容使用out对象。
<%
    //以下四句在不加out.flush();情况下
    //PrintWriter跑到最上面去了, 因为out有8kb的缓存,PrintWriter的直接进入了响应体
    //而out写完后等页面自动刷新后才写入响应体,加 out.flush();进行刷入
    out.print("测试out输出内容到界面!<br/>");
    out.flush();
    PrintWriter out2 = response.getWriter();
    out2.print("测试另一种输出方式<br/>");
%>
  • jsp的out和getWriter()方法的区别
    • out是JspWriter类型,getWriter()是PrintWriter类型。
    • out输出到8k缓冲区中,没有写到response中,getWriter()直接写到response中。
    • out一般用在jsp中,getWriter()用在Servlet中
    • 如果混用,要及时刷新缓冲区。

pageContext 对象

  • pageContext:
    • 代表整个JSP页面,当前页面的作用域对象,只在当前页面中使用。
  • 作用:
    • 作为域(容器)对象。
    • 用于获取其他八个内置对象。
  • 操作当前页面域
    • pageContext.setAttribute("name",value);
    • pageContext.getAttribute("name");
    • pageContext.removeAttribute("name");
    String name = "lz";
    pageContext.setAttribute("username", name);
    String username = (String) pageContext.getAttribute("username");
    out.print(username);
    pageContext.removeAttribute("username");
  • 操作其他域对象:
    • pageContext.setAttribute("name",value,域范围)。
    • 域范围:
      • REQUEST_SCOPE
      • SESSION_SCOPE
      • APPLICATION_SCOPE
      • PAGE_SCOPE
<%
    //操作其他三个与对象  request response application(ServletContext)
    pageContext.setAttribute("requestData", "beijing", PageContext.REQUEST_SCOPE);
    pageContext.setAttribute("sessionData", "wl", PageContext.SESSION_SCOPE);
    pageContext.setAttribute("applicationData", "lz", PageContext.APPLICATION_SCOPE);
    //做一个转发,在data.jsp页面接收数据打印
    request.getRequestDispatcher("data.jsp").forward(request, response);
%>

data.jsp

<%
    String requestData = (String) request.getAttribute("requestData");
    String sessionData = (String) session.getAttribute("sessionData");
    String applicationData = (String) application.getAttribute("applicationData");

    out.print(requestData);
    out.print(sessionData);
    out.print(applicationData);
%>
<%
    //移除数据 page request  response  application
    //不用指定域,它会从这四个域中挨个移除
    pageContext.removeAttribute("requestData");
    pageContext.removeAttribute("sessionData");
    pageContext.removeAttribute("applicationData");
%>
  • pageContext.findAttribute("name");
    • 从四个域中依次查找:从pageContext、request、session、application,找到为止。
    • 如果都没有则返回null。
<%
    //查找数据依次从 page ->  request -> response -> application
    //中查找数据,pageContext.findAttribute("");
    String requestData = (String) pageContext.findAttribute("requestData");
    String sessionData = (String) pageContext.findAttribute("sessionData");
    String applicationData = (String) pageContext.findAttribute("applicationData");
%>

四大域对象

四大作用域对象,存储和获取数据的方式一样,不同的是取值的范围有差别。

使用原则:能用小范围,就不使用大范围。

EL表达式

概念:

  • EL使JSP写起来更简单、简洁。主要用于获取作用域中的数据。减少在JSP中java的代码。
  • java代码和前端代码柔和在一起也不利于代码的维护。

作用:

  • 用于替换:域对象.getAttribute("name")。

应用:

  • ${scope.name} 获取具体某个作用域中的数据。
  • ${name} 获取作用域中的数据,四个域逐级查找。

EL获取简单数据

从域中取数据前,必须先数据放入域中。

获取简单的数据:

<%
    pageContext.setAttribute("username", "lz");
%>
<%--不使用 EL表达式--%>
<%=pageContext.findAttribute("username")%>
<%--使用 EL表达式--%>
<%--${"username"}  打印username--%>
${username} 

获取对象的属性

User

public class User {
  private String name;
  private int age;
  private Address address;
}

Address

public class Address {
  private String address;
}
<%
    User user = new User("wl", 20);
    pageContext.setAttribute("user", user);
    user.setAddress(new Address("泰国"));
    pageContext.setAttribute("user", user);
%>
${user.name}
${user.age}
${user.address.address}

获取数组、List\Map集合的内容:

<%
    int[] arr = {1, 2, 3, 4};
    pageContext.setAttribute("arr", arr);

    ArrayList<Address> list = new ArrayList<>();
    list.add(new Address("beijing"));
    pageContext.setAttribute("list", list);

    HashMap<String, String> map = new HashMap<>();
    map.put("cn", "中国");
    pageContext.setAttribute("map", map);
%>

${arr[0]}

${list[0]}
${list.get(0)}

${map['cn']}
${map.cn}
${map.get('cn')}

EL和JSP脚本的区别

  • <%=request.getAttribute(name) %>,没有找到返回null
  • ${name},没找到返回""。

EL运算符

    <%
        pageContext.setAttribute("address1", new String("北京"));
        pageContext.setAttribute("address2", new String("北京"));
        pageContext.setAttribute("address3", "");
        pageContext.setAttribute("list", new ArrayList<>());
    %>
    <h1>EL表达式运算符的使用</h1>
    <h2>算术运算符</h2>
    ${100+200}<br/>
    ${100-20}<br/>
    ${100*5}<br/>
    ${10/4}<br/>
    ${10%3}<br/>
    <h2>关系运算符</h2>
    ${10==15}<br/>
    ${"abc"=="abc"}<br/>
    ${"abc" eq "abc"}<br/>
    <!-- true -->
    ${address1==address2}<br/>
    ${10>8}<br/>
    ${10 gt 8}<br/>
    ${10<8}<br/>
    ${10 lt 8}<br/>
    ${10 >=8}<br/>
    ${10 ge 8}<br/>
    ${10 <=8}<br/>
    ${10 le 8}
    <h2>逻辑运算符</h2>
    ${true&&false}<br/>
    ${true||false}<br/>
    ${!true}<br/>

    <h2>三目运算符</h2>
    ${user==null ? "没有登录":user.username}<br/>
    ${flag==1?"激活":"没有激活"}<br/>
    
    <h2>empty:判断为空 (1)对象为null (2)字符串空 null or "" (3)集合没有元素</h2>
    ${empty user? "没有登录":user.username}<br/>
    <!-- true -->
    ${empty address3}<br/>
    <!-- true -->
    ${empty list}

隐式对象

EL 表达式语言定义了11个隐式对象。

    <h1>EL表达式的11个隐式对象</h1>
    <ul>
        <li>pageScope:pageContext域里的集合</li>
        <li>requestScope:request域</li>
        <li>sessionScope:session域</li>
        <li>applicationScope:application域</li>
        <li>param:request的参数</li>
        <li>paramValues: request的参数</li>
        <li>header:请求头</li>
        <li>headerValues:请求头 数组</li>
        <li>initParams:ServletContext参数</li>
        <li>cookie:获取cookie</li>
        <li>pageContext:页面上下文对象本身</li>
    </ul> 

前四个使用格式:

    <%
        pageContext.setAttribute("username", "hello");
     %>
    ${pageScope.username}<br/>

param:获取request中的参数

    <%
       String gender = request.getParameter("gender");
       out.println(gender);
    %>
    ${param.gender}<br/>

paramValues: 获取多个request的参数

    ${paramValues.hobby[0]}
    ${paramValues.hobby[1]}

header:获取请求头里的参数

${header.accept}等

initParams:ServletContext参数

web.xml

    <!--全局ServletContext参数-->
    <context-param>
        <param-name>appName</param-name>
        <param-value>我的淘宝</param-value>
    </context-param>
    ${initParam.appName}

cookie:获取cookie

    ${cookie.JSESSIONID.name}... ${cookie.JSESSIONID.value}

pageContext:页面上下文对象本身

    ${pageContext.request}<br/>
    <%--${pageContext.response}<br/>--%>
    <%--${pageContext.session}<br/>--%>
    <%--${pageContext.servletContext}<br/>--%>
    <%--${pageContext.servletConfig}<br/>--%>
    <%--${pageContext.out}<br/>--%>
    <%--${pageContext.exception}<br/>--%>
    <%--${pageContext.page}<br/>--%>

作用 作为参数传递

public class JspUtils {
    public static void process(PageContext pageContext){

    }
}

获得应用上下文路径(/web1)${pageContext.request.contextPath}

路径分类

问题描述:在项目web目录下创建images文件夹,放入两张照片,在web目录下创建一个JSP页面引入头部、尾部

header.jsp于footer.jsp中分别添加图片

启动tomcat这时可以正常访问,但若将创建的JSP文件访问非web根目录下的其他文件夹中,这时访问不到图片,运行结果网页源码如下图。

可以看到地址是相对路径在当前目录下寻找,而图片在他的上一级目录中。

那怎么办呢? 继续看下去吧。

  • 1.使用绝对路径: 用在不同网站之间的跳转。
    • 比如:http://localhost:8080/images/1.jpg
    • 有些参数没有必要去写
  • 2.相对路径: 用在同一个主机或域名中, aaa/1.jpg。
    • 如果页面比较多,并且在不同的目录下,并且使用框架或模板,会出现混乱。
    • 相对就会有参照,不同的页面可能参照点不同,会出现找到不到的情况
  • 3.根路径: 特殊的相对路径,相对整个网站的根目录(域名或主机名)
    • 如果在浏览器中使用,/ 表示主机名或域名,比如http://localhost:8080/
    • 如果在服务器中使用, / 表示上下文路径,比如/myweb

红圈部分表示http://localhost:8080/web1 ,其中web1是你tomcat自己配置的。所以固定性是不好的选择,需要动态的获取你配置的路径:

前面不需要再写/,因为返回的就是 /web1这种格式。

转发:

         //转发时路径写上/  , /表示web应用上下文路径,/的前面已经有了 day40web1
        //在服务器转发,服务器是知道应用在哪里
        request.getRequestDispatcher("/index.jsp").forward(request,response );

重定向

        //1.相对路径
         response.sendRedirect("index.jsp");
        //2.根路径  
        //重定向时路径写/ , /表示主机名或域名 localhost:8080
        //没有项目名所以找不到
        response.sendRedirect("/index.jsp");

解决方法:写上项目名

        response.sendRedirect("day40web1/index.jsp");

同样不能写死:

        response.sendRedirect(request.getContextPath()+"/index.jsp");

EL问题?

  • EL主要用于域对象获取数据。
  • EL不存在流程控制,比如判断。
  • EL对于集合只能元素单独访问,不能实现遍历操作,比如循环。
<%
    List<String> list=new ArrayList();
    list.add("华为");
    list.add("苹果");
    list.add("小米");
    list.add("vivo");
    list.add("oppo");
    pageContext.setAttribute("list", list);
%>

${list[0]}<br/>
${list[1]}<br/>
${list[2]}<br/>
${list[3]}<br/>
${list[4]}<br/>

数据少还可以一个一个打印,但是多了就麻烦了。

JSTL

  • JSP标准标签库:
    • 是一个JSP标签集合。
    • 是由JCP(Java Community Process)所制定的标准规范,它主要提供给Java Web开发人员一个标准通用的标签库,并由Apache的Jakarta小组来维护。
    • 开发人员可以利用这些标签取代JSP页面上的Java代码,从而提高程序的可读性,降低程序的维护难度。

Java Server Pages Standard Tag Library : JSTL标准标签库

作用:

  • 可对EL获取到的数据进行逻辑操作。
  • 与EL配合完成数据的展示。

JSTL不在tomcat中去maven仓库里找。添加完依赖后,在JSP页面中导入依赖:

<!-- prefix 前缀 可以自定义 -->
<!-- uri 统一资源标识符 -->
<!-- 核心内容 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 格式化内容 -->
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

set、out、remove

三个通用的标签:set、out、remove

set:向域中添加数据

    <%--
        set标签:
            var:变量名
            value:值
            scope: 域范围  默认page
    --%>
    <c:set var="username" value="admin"></c:set>
    <!-- 相当于 -->
    <%
        pageContext.setAttribute("username","admin");
    %>

out:从域中获取数据

    ${username}<br/>
    <%--
        value:输出谁的值
    --%>
    <c:out value="${username}"></c:out><br/>

既然有了${},那为什么还要用<c:out>呢?当然是为了防止攻击。

    <c:set var="myjs" value="<script>while(true){alert('点击我中奖了...')}</script>"></c:set>
    ${myjs}
    <c:out value="${myjs}"></c:out>

当使用${myjs}会执行JS代码,而<c:out>显示的字符串。

这种攻击称为XSS攻击,跨站脚本攻击。扩展SQL注入。

remove:从域中删除数据

    <%--
        var: 删除的变量名
    --%>
    <c:remove var="username"></c:remove>
    ${username}

条件标签if

<c:if>标签判断表达式的值,如果表达式的值为true。

语法:<c:if test = "条件">< /c:if>

    <c:if test="${10>8}">
        <p>日照香炉生紫烟</p>
    </c:if>
    <c:if test="${empty user}">
        没有登录
    </c:if>

多分支标签choose

<c:choose>标签与多重if语句功能一样,用于在众多选项中做出选择。

    <h2>3 多分支标签choose的使用</h2>
    <c:set var="score" value="61"></c:set>
    <c:choose>
        <c:when test="${score>90}">优秀</c:when>
        <c:when test="${score>80}">良秀</c:when>
        <c:when test="${score>60}">一般</c:when>
        <c:otherwise>
            较差
        </c:otherwise>
    </c:choose>

迭代foreach标签

foreach封装了Java中的for,while,do-while循环。

语法:

    <%
        List<String> list=new ArrayList();
        list.add("华为");
        list.add("苹果");
        list.add("小米");
        list.add("vivo");
        list.add("oppo");
        pageContext.setAttribute("list", list);
    %>
    <h2>4 forEach标签的使用</h2>
    <%--
        items: 遍历的集合或数组
        var:变量名
        begin: 开始数字
        end: 结束数字
        step: 步长
        varStaus: 变量状态
                index:下标
                count:个数
    --%>
    <c:forEach items="${list}" var="con" varStatus="vs">
        ${con}....${vs.index}...${vs.count}...${vs.first}....${vs.last}<br/>
    </c:forEach>
    <!-- 输出1-10 步长为2 -->
    <c:forEach begin="0" end="10" var="n" step="2">
        ${n}<br/>
    </c:forEach>

url标签

  • <c:url>标签将URL格式化为一个字符串,然后存储在一个变量中。
  • 自动重写URL,如果有中文自动编码。
  • var属性用于存储格式化后的URL。
    <c:url var="myurl" value="index.jsp?address=北京">
        <c:param name="username" value="张三"></c:param>
    </c:url>
    <a href="${myurl}">跳转到首页</a>

fmt标签

fmt:formatDate 格式时间标签

    <%
        pageContext.setAttribute("bornDate", new Date());
    %>
    ${bornDate}<br/>
    <fmt:formatDate value="${bornDate}" pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>

MVC模式

MVC与三层架构对应关系

  • Web层对应MVC中的Controller(Servlet)和View(JSP、Html)
  • 其他层都属于MVC中的Model

项目

  • day41
    • 事务转账
    • CRUD操作
    • 重复提交问题
  • day42
    • 分页
    • 上传下载文件
  • day43
    • 过滤器
    • 禁用浏览器缓存
    • 过滤脏词
    • 内容压缩
  • day44
    • 监听器

[/wppay]