JavaWeb 开发 04 —— JSP(原理、语法、指令、内置对象、JSP标签、JSTP标签)、JavaBean、MVC
系列文章JavaWeb 开发 01 —— 基本概念、Web服务器、HTTP、MavenJavaWeb 开发 02 —— ServletContext、读取资源、下载文件、重定向和请求转发JavaWeb 开发 03 —— Cookie 和 SessionJavaWeb 开发 04 —— JSP(原理、语法、指令、内置对象、JSP标签、JSTP标签)、JavaBean、MVC文章目录系列文章7、JSP
系列文章
JavaWeb 开发 01 —— 基本概念、Web服务器、HTTP、Maven
JavaWeb 开发 02 —— ServletContext、读取资源、下载文件、重定向和请求转发
JavaWeb 开发 03 —— Cookie 和 Session
JavaWeb 开发 04 —— JSP(原理、语法、指令、内置对象、JSP标签、JSTP标签)、JavaBean、MVC
文章目录
7、JSP
当我们只更新了JSP的代码时,不需要重启Tomcat,只需要更新资源就好。
JSP即Java Server Pages(Java 服务器端页面),和Servlet一样,用于动态Web技术。
- 写JSP就像写HTML
- 区别:
- HTML只给用户提供静态的数据
- JSP页面可以嵌入Java代码,为用户提供动态数据
7.1、JSP原理
JSP原理流程图:
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注释依然可以通过源码看见。
这是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>
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>
结果:
关于@include和jsp:include的区别:
在_jspService方法的源码中,用@include,是把两个.jsp文件的内容通过out输出,相当于合并到了原本的HTML代码。而通过jsp:include方式,则是导入两个jsp资源。
下面用更通俗的例子解释:在test.jsp和header.jsp都定义同名变量 i,会报错。
但通过jsp:include则不会,所以一般我们都用jsp:include,更加灵活。
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输出。
当我们跳转到pageContextDemo2.jsp来取出值时,小白1和小白2是空,因为小白1只在一个页面有效,而小白2此时没有将请求转发到第二个页面,所以也为空。我们在pageContextDemo1.jsp后面加上一行请求转发的代码,就能实现小白2。
在最后加上代码
//两种均可,第一种常用于前端,第二种用于后端
pageContext.forward("/pageContextDemo2.jsp");
request.getRequestDispatcher("/pageContextDemo02.jsp").forward(request, response);
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>
结果:
JSTL标签
JSTL标签是为了弥补HTML标签的不足,让代码更加优美和简介,实际上JSTL标签做的事完全可以用Java代码完成。
这里主要使用核心标签中常用的,详细请看 菜鸟教程: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>
结果:
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>
结果:
<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>
结果:
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
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、早些年架构
用户直接访问控制层,控制层就可以直接操作数据库。
servlet——CRUD(增删改查)——数据库
弊端:程序十分臃肿,不利于维护。
Servlet的代码中,既要处理请求响应、视图跳转,还要处理JDBC、业务代码、逻辑代码。
9.2、MVC三层架构
Model:
- 业务处理:业务逻辑(Service)
- 数据持久层:CRUD增删改查(DAO Data Access Object数据访问对象,用来操作数据)
View:
- 展示数据
- 提供链接发起Servlet(a、form、img标签)
Controller(Servlet):
- 接受用户的请求:req 请求参数、Session信息
- 交给业务测处理对应代码
- 控制视图跳转
登录->接受用户的登录请求—>处理用户的请求(获取用户登录的参数,username、password)—>交给业务层处理登录业务(判断用户名和密码是否正确:事务)—>DAO层查询用户名和密码是否正确—>数据库
更多推荐
所有评论(0)