系列文章

JavaWeb 开发 01 —— 基本概念、Web服务器、HTTP、Maven

JavaWeb 开发 02 —— ServletContext、读取资源、下载文件、重定向和请求转发

JavaWeb 开发 03 —— Cookie 和 Session

JavaWeb 开发 04 —— JSP(原理、语法、指令、内置对象、JSP标签、JSTP标签)、JavaBean、MVC

JavaWeb 开发 05 —— 过滤器、监听器

JavaWeb 开发 06 —— smbms项目实践



7、JSP

当我们只更新了JSP的代码时,不需要重启Tomcat,只需要更新资源就好。

1613566441696 1613566420320

JSP即Java Server Pages(Java 服务器端页面),和Servlet一样,用于动态Web技术。

  • 写JSP就像写HTML
  • 区别:
    • HTML只给用户提供静态的数据
    • JSP页面可以嵌入Java代码,为用户提供动态数据

 

7.1、JSP原理

JSP原理流程图:

1613544383059

JSP本质上还是一个Servlet,当我们在JSP中写HTML代码时,相当于Servlet中对这些HTML代码输出,当我们在JSP中写Java代码时,Servlet就原封不动的运行Java代码。

先编写一个JSP,并运行Tomcat,然后进入该页面
 
test.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
</head>
<body>
    <% String name = "ABC"; %>
    name: <%= name %>
</body>
</html>

在这里插入图片描述

然后在我的电脑上,进入IDEA的Tomcat,下面是我的路径

C:\Users\11427\.IntelliJIdea2019.3\system\tomcat\Unnamed_JavaWeb_01\work\Catalina\localhost\myWeb\org\apache\jsp

在这里插入图片描述
 
其中,test_jsp.java就是我们刚刚创建的jsp文件转变过来的,当我们访问了该JSP页面后,Tomcat就会把相应的JSP转为Servlet类。该类继承HttpJspBase,而HttpJspBase又继承HttpServlet。现在我们进去看看。

在代码中最关键的函数就是_jspService,可以看到,这个函数通过write将HTML代码输出,并且将Java代码保留。

response.setContentType("text/html;charset=UTF-8");
out.write("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("    ");
String name = "ABC"; 
out.write("\r\n");
out.write("    name: ");
out.print( name );
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");

 

7.2、JSP基础语法

pom.xml需要以下依赖

<dependencies>
    <!-- Servlet依赖 -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    <!-- JSP依赖 -->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.3</version>
        <scope>provided</scope>
    </dependency>

    <!-- JSTL表达式依赖 -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>

    <!-- standard标签库 -->
    <dependency>
        <groupId>taglibs</groupId>
        <artifactId>standard</artifactId>
        <version>1.1.2</version>
    </dependency>
</dependencies>

JSP作为Java技术的一种应用,它拥有一些扩充的语法(了解即可),同时Java的语法它都支持!
 
JSP的语法:

<% 这里面放Java代码,代码都在于_jspService方法里,JSP转为Servlet后的java文件%>
<%= 这里面放变量或者表达式,_jspService方法会输出这里面的变量或表达式的值 %>
<%! 这里面是全局的作用域,即不在_jspService方法,而是属于类的成员%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
</head>
<body>
    <!-- 这是HTML注释 -->
    <%-- 这是JSP注释 --%>
    <%!
        private int i;
        public void sout(){
            System.out.println("Servlet的方法");
        }
    %>

    <% for (i = 1; i <= 3; i++) { %>
    <p>Hello <%=i%></p>
    <% } %>
    <% sout(); %>
</body>
</html>

 
结果:查看源码里的注释,发现HTML注释依然可以通过源码看见。

1613546700473

这是test_jsp中的sout方法,以及_jspService方法中对应的片段

在这里插入图片描述

out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("    <!-- 这是HTML注释 -->\r\n");
out.write("    ");
out.write("\r\n");
out.write("    ");
out.write("\r\n");
out.write("    ");
out.write("\r\n");
out.write("    ");
for (i = 1; i <= 3; i++) { 
    out.write("\r\n");
    out.write("    <p>Hello ");
    out.print(i);
    out.write(',');
    out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${i}", java.lang.String.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null));
    out.write("</p>\r\n");
    out.write("    ");
} 
out.write("\r\n");
out.write("    ");
sout(); 
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");

 

7.3、JSP指令

创建好JSP的第一行代码就是一种指令,指定该JSP的类型以及语言。

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

 
page指令

下面通过指令方式来定制错误页面(例如404、500),但这种方式是只要发生错误,就跳转到该页面。偷懒写前端,就先去网上随便找两张404、500的图。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 无论是什么错误,都跳转到同一个页面-->
<%@ page errorPage="error/500.jsp" %>
<html>
<head>
</head>
<body>
    <% int x = 1/0;%>
</body>
</html>

 
第二种,修改web.xml代码,这种可以指定各种错误代码的页面。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <error-page>
        <error-code>404</error-code>
        <location>/error/404.jsp</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/error/500.jsp</location>
    </error-page>
</web-app>
1613549035951 1613549078311

 
include指令

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
</head>
<body>
    <%-- 1. 指令方式 @include 会将页面合并--%>
    <%@include file="/common/header.jsp"%>
    <h1>网页主体</h1>
    <%@include file="/common/footer.jsp"%>

    <%-- 2. 标签方式 jsp:include 是拼接页面,本质上还是三个 --%>
    <jsp:include page="common/header.jsp"/>
    <h1>网页主体2</h1>
    <jsp:include page="common/footer.jsp"/>
</body>
</html>

 
结果:

1613550699865

关于@include和jsp:include的区别:

在_jspService方法的源码中,用@include,是把两个.jsp文件的内容通过out输出,相当于合并到了原本的HTML代码。而通过jsp:include方式,则是导入两个jsp资源。

1613550857095

下面用更通俗的例子解释:在test.jsp和header.jsp都定义同名变量 i,会报错。

在这里插入图片描述

1613551214419 1613551245783

但通过jsp:include则不会,所以一般我们都用jsp:include,更加灵活。

1613551350299

 

7.4、九大内置对象

  • PageContext 存东西的
  • Request 存东西的
  • Response
  • Session 存东西的
  • Application【就是ServletContext】存东西的
  • Config【就是ServletConfig】
  • out,用于输出,和Servlet的PrintWriter类似。
  • page,几乎不用,无需了解。
  • exception,就是Java的异常。

这里主要讲这几个存东西对象的区别。

pageContextDemo1.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%-- 内置对象 --%>
    <%
        //保存的数据只在一个页面有效
        pageContext.setAttribute("name1", "page 小白1号");
        //第三个参数,可以改变作用域
        pageContext.setAttribute("name0", "page->application 小白0号", PageContext.APPLICATION_SCOPE);
        //保存的数据只在一次请求中有效,但请求转发会携带这个数据
        request.setAttribute("name2", "request 小白2号");
        //保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器(未设置有效期的前提下)
        session.setAttribute("name3", "session 小白3号");
        //保存的数据只在服务器中有效,从打开服务器到服务器关闭
        application.setAttribute("name4", "application 小白4号");
    %>
    <%
        //可以通过getAttribute去,也可以用pageContext的findAttribute方法找到
        String name0 = (String) pageContext.findAttribute("name0");
        String name1 = (String) pageContext.findAttribute("name1");
        String name2 = (String) pageContext.findAttribute("name2");
        String name3 = (String) pageContext.findAttribute("name3");
        String name4 = (String) pageContext.findAttribute("name4");
        String name5 = (String) pageContext.findAttribute("name5");
    %>
    <h1>取出的值</h1>
    <h3><%= name0 %></h3>
    <h3><%= name1 %></h3>
    <h3><%= name2 %></h3>
    <h3><%= name3 %></h3>
    <h3><%= name4 %></h3>
    <h3><%= name5 %></h3>
    <%-- 用<%= %>取出null,而EL表达式不会    --%>
    ${name5}
</body>
</html>

pageContextDemo2.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        String name0 = (String) pageContext.findAttribute("name0");
        String name1 = (String) pageContext.findAttribute("name1");
        String name2 = (String) pageContext.findAttribute("name2");
        String name3 = (String) pageContext.findAttribute("name3");
        String name4 = (String) pageContext.findAttribute("name4");
        String name5 = (String) pageContext.findAttribute("name5");
    %>
    <h1>取出的值</h1>
    <h3><%= name0 %></h3>
    <h3><%= name1 %></h3>
    <h3><%= name2 %></h3>
    <h3><%= name3 %></h3>
    <h3><%= name4 %></h3>
    <h3><%= name5 %></h3>
    <%-- 用<%= %>取出null,而EL表达式不会    --%>
    ${name5}

</body>
</html>

 
结果:

可以发现,<%= %>这种方式会得出null,而用EL表达式 ${}不会将null输出。

1613565476241

当我们跳转到pageContextDemo2.jsp来取出值时,小白1和小白2是空,因为小白1只在一个页面有效,而小白2此时没有将请求转发到第二个页面,所以也为空。我们在pageContextDemo1.jsp后面加上一行请求转发的代码,就能实现小白2。

1613565541757

在最后加上代码

//两种均可,第一种常用于前端,第二种用于后端
pageContext.forward("/pageContextDemo2.jsp");
request.getRequestDispatcher("/pageContextDemo02.jsp").forward(request, response);
1613566068310

 

7.5、EL表达式、JSP标签、JSTL标签

<!-- JSTL表达式依赖 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

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

 

EL表达式:${ }

  • 获取数据
  • 执行运算
  • 获取Web开发常用对象

具体使用看JSTL标签处的代码。
 

JSP标签

tag1.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Tag1</h1>
    <%-- 标签 jsp:include   --%>
    <%-- 类似请求转发,可以携带参数——> http://localhost:8080/tag1.jsp?a=1&n=2 --%>
    <jsp:forward page="tag2.jsp">
        <jsp:param name="a" value="1"/>
        <jsp:param name="b" value="2"/>
    </jsp:forward>
</body>
</html>

tag2.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Tag2</h1>
    <h2>参数</h2>
    a:<%= request.getParameter("a")%>
    b:<%= request.getParameter("b")%>
</body>
</html>

结果:

1613566830074

 

JSTL标签

JSTL标签是为了弥补HTML标签的不足,让代码更加优美和简介,实际上JSTL标签做的事完全可以用Java代码完成。

1613569016681

这里主要使用核心标签中常用的,详细请看 菜鸟教程:JSP标准标签库(JSTL)

使用前需要导入前面dependency的两个包,不仅仅是IDEA,电脑上的的Tomcat也需要有,可以直接从IDEA项目复制到Tomcat的lib目录下。
 
<c:if test=“条件” var=“结果”>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/myWeb/coreIf.jsp">
        <%--通过EL表达式获取表单数据,${param.参数名},这里将input的值放在param.password中--%>
        密码:<input type="password" name="password" value="${param.password}"><br/>
        <input type="submit" value="提交">
    </form>
    <%-- 通过EL表达式进行表达式计算,结果由test赋值给var里的参数    --%>
    <c:if test="${param.password.equals('123456')}" var="isTrue">
        <c:out value="密码正确"/>
    </c:if>
    <%-- 变量 isTrue 存储bool值    --%>
    <c:out value="${isTrue}"/>
</body>
</html>

结果:

1613569656429

choose和when

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--将值value存放于变量score中--%>
    <c:set var = "score" value="${85}"/>
    <%-- 类似于Java的switch--%>
    <c:choose>
        <c:when test="${score >= 90}">优秀</c:when>
        <c:when test="${score >= 75}">良好</c:when>
        <c:when test="${score >= 60}">合格</c:when>
        <c:otherwise>不合格</c:otherwise>
    </c:choose>
</body>
</html>

结果:

1613570073499

<c:forEach var=" " items=" ">

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        int[] array = {0,1,2,3,4,5};
        //需要放到request中,或者放session,pageContext等都可以
        request.setAttribute("items",array);
    %>
    <%--
        var:每一次取出的值
        items:待遍历的值
        begin:起始位置
        end:终止位置
        step:步长
    --%>
    <c:forEach var="x" items="${items}" begin="1" end="4" step="1">
        <c:out value="${x}"/>
    </c:forEach>
</body>
</html>

结果:

1613570581749

 

8、JavaBean

JavaBean就是实体类,但它由特定的写法:

  • 必须要由一个无参构造
  • 属性必须私有化
  • 必须由对应的get/set方法

一般用于和数据库的字段做映射 ORM:

  • ORM:对象关系映射
  • 表——>类
  • 字段——>属性
  • 一行记录——>一个对象

数据库可以看我另一篇博客 数据库 —— Java操作MySQL

People.java,这就是一个JavaBean

package com.zcy.pojo;

public class People {
    private int id;
    private String name;
    private int age;
    private String address;

    public void setId(int id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getAddress() {
        return address;
    }

    public People() {
    }

    public People(int id, String name, int age, String address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.address = address;
    }
}

对应数据库中的表 people

1613612998060

javabean.jsp,在JSP中使用JavaBean

<%@ page import="com.zcy.pojo.People" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--<%
        People people = new People();
        people.setId(10000);
        people.setName("小白");
        people.setAge(18);
        people.setAddress("北京");

        out.print(people.getName()+"现在"+people.getAge()+"岁了!");
    %>--%>
    <%-- 等价于上面 --%>
    <jsp:useBean id="people" class="com.zcy.pojo.People" scope="page"/>
    <jsp:setProperty name="people" property="id" value="10000"/>
    <jsp:setProperty name="people" property="name" value="小白"/>
    <jsp:setProperty name="people" property="age" value="18"/>
    <jsp:setProperty name="people" property="address" value="北京"/>
    <jsp:getProperty name="people" property="name"/>现在<jsp:getProperty name="people" property="age"/>岁了!

</body>
</html>

结果:

在这里插入图片描述

 

9、MVC三层架构

MVC:Model 模型、View 视图、Controller 控制器

9.1、早些年架构

1613613865942

用户直接访问控制层,控制层就可以直接操作数据库。

servlet——CRUD(增删改查)——数据库
弊端:程序十分臃肿,不利于维护。
Servlet的代码中,既要处理请求响应、视图跳转,还要处理JDBC、业务代码、逻辑代码。

 

9.2、MVC三层架构

1613614794461

Model:

  • 业务处理:业务逻辑(Service)
  • 数据持久层:CRUD增删改查(DAO Data Access Object数据访问对象,用来操作数据)

View:

  • 展示数据
  • 提供链接发起Servlet(a、form、img标签)

Controller(Servlet):

  • 接受用户的请求:req 请求参数、Session信息
  • 交给业务测处理对应代码
  • 控制视图跳转
登录->接受用户的登录请求—>处理用户的请求(获取用户登录的参数,username、password)—>交给业务层处理登录业务(判断用户名和密码是否正确:事务)—>DAO层查询用户名和密码是否正确—>数据库
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐