JSP & MVC
案例目标
- 企业通讯录
分析
实现
-
ContactProfile.java
package com.itheima.domain; /** * 通讯录用户信息 * * @author itcast */ public class ContactProfile { /// 编号 private int no; /// 姓名 private String name; /// 性别 private String gender; /// 出生日期 private long birthday; /// 出生地 private String birthplace; /// 手机号码 private String mobile; /// 邮箱 private String email; public ContactProfile() { } public ContactProfile(int no, String name, String gender, long birthday, String birthplace, String mobile, String email) { this.no = no; this.name = name; this.gender = gender; this.birthday = birthday; this.birthplace = birthplace; this.mobile = mobile; this.email = email; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public long getBirthday() { return birthday; } public void setBirthday(long birthday) { this.birthday = birthday; } public String getBirthplace() { return birthplace; } public void setBirthplace(String birthplace) { this.birthplace = birthplace; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
-
ContactsFactory.java
package com.itheima.domain; import java.util.LinkedList; import java.util.List; /** * 通讯录工厂,用于批量生产通讯录用户信息,实际项目中将会采用JDBC技术从数据库读取 * * @author itcast */ public class ContactsFactory { public static List<ContactProfile> produce() { List<ContactProfile> result = new LinkedList<>(); result.add(new ContactProfile(1, "张三", "male", 11, "广州", "134-0000-0000", "zhangsan@itcast.cn")); result.add(new ContactProfile(2, "李四", "male", 12, "上海", "134-0000-0001", "lisi@itcast.cn")); result.add(new ContactProfile(3, "王五", "female", 13, "广州", "134-0000-0002", "wangwu@itcast.cn")); result.add(new ContactProfile(4, "赵六", "male", 14, "北京", "134-0000-0003", "zhaoliu@itcast.cn")); result.add(new ContactProfile(5, "田七", "female", 15, "广州", "134-0000-0004", "tianqi@itcast.cn")); return result; } }
-
ContactServlet.java
package com.itheima.web; import com.itheima.domain.ContactProfile; import com.itheima.domain.ContactsFactory; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.List; @WebServlet("/contact") public class ContactServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html; charset=utf-8"); PrintWriter out = response.getWriter(); List<ContactProfile> users = ContactsFactory.produce(); out.println("<!DOCTYPE html>"); out.println("<html lang='en'>"); out.println("<head>"); out.println("<link rel='stylesheet' href='css/bootstrap-grid.min.css'/>"); out.println("<link rel='stylesheet' href='css/bootstrap-reboot.min.css'/>"); out.println("<link rel='stylesheet' href='css/bootstrap.min.css'/>"); out.println("<script src='js/jquery-3.3.1.min.js'></script>"); out.println("<script src='js/vue.min.js'></script>"); out.println("<script src='js/bootstrap.bundle.min.js'></script>"); out.println("<script src='js/bootstrap.min.js'></script>"); out.println("<meta charset='UTF-8'>"); out.println("<title>Title</title>"); out.println("</head>"); out.println("<body>"); out.println("<table class='table table-striped'>"); out.println("<tr>"); out.println("<th>编号</th>"); out.println("<th>姓名</th>"); out.println("<th>性别</th>"); out.println("<th>年龄</th>"); out.println("<th>籍贯</th>"); out.println("<th>手机</th>"); out.println("<th>邮箱</th>"); out.println("</tr>"); for (ContactProfile profile : users) { out.println("<tr>"); out.println("<td>" + profile.getNo() + "</td>"); out.println("<td>" + profile.getName() + "</td>"); out.println("<td>" + (profile.getGender().equals("male") ? "男" : "女") + "</td>"); out.println("<td>" + profile.getBirthday() + "</td>"); out.println("<td>" + profile.getBirthplace() +"</td>"); out.println("<td>" + profile.getMobile() + "</td>"); out.println("<td>" + profile.getEmail() + "</td>"); out.println("</tr>"); } out.println("</table>"); out.println("</body>"); out.println("</html>"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
总结
Servlet制作动态资源的缺点
- 在Java代码当中嵌入HTML代码,IDEA无法检查字符串内部的HTML语法错误
- 需要使用字符流输出
- Java相应的关键字需要转义后才能使用
结论
- Servlet是在Java代码当中嵌入HTML代码
- JSP是在HTML代码当中嵌入Java代码
第一部分 JSP入门
1 JSP概述
JavaServer Pages (JSP) technology lets you put snippets of servlet code directly into a text-based document. A JSP page is a text-based document that contains two types of text:
- Static data, which can be expressed in any text-based format, such as HTML or XML
- JSP elements, which determine how the page constructs dynamic content
2 JSP运行原理
- Idea部署Tomcat的Web项目目录
Mac: /Users/${user}/Library/Caches/IntelliJIdea${version}/tomcat/work
Linux: /home/${user}/.IntelliJIdea${version}/system/tomcat/work
Windows: C:\Users\${user}\.IntelliJIdea${version}\system\tomcat\work
JSP本质就是Servlet
- Servlet
- JSP
3 JSP脚本和注释
JSP脚本
-
<% Scriptlet %>【掌握】
内部的Java代码翻译到service方法的内部
-
<%= 表达式 %>【掌握】
会被翻译成service方法内部out.print(表达式)
-
<%! 声明 %>【了解】
会被翻译成Servlet的成员的内容
JSP注释
不同的注释,可见范围不同
-
HTML注释
<!-- 注释内容 -->
可见范围
-
JSP源码
-
翻译后的Servlet
-
页面显示HTML源码
-
-
Java注释
//单行注释 /* 多行注释 */ /** * Java 文档注释 */
可见范围
-
JSP源码
-
翻译后的Servlet
-
-
JSP注释【掌握】
<%-- 注释内容 --%>
可见范围
- JSP源码可见
小结
-
Scriptlet
<% Java代码 %>
-
表达式
<%= 表达式 %>
-
声明【了解】
<%! %>
4 JSP指令(3个)
JSP的指令是指导JSP翻译和运行的命令,JSP包括三大指令:
page指令【了解】
<%@ page 属性名1 = "属性值1" 属性名2 = "属性值2" %>
属性名 | 描述 |
---|---|
language | JSP脚本中可以嵌入的语言种类 |
pageEncoding | 当前JSP文件的本身编码,内部可以包含contentType |
contentType | response.setContentType(text/html;charset=UTF-8) |
session | 是否JSP在翻译时自动创建session |
extends | 修改JSP翻译后的Servlet的继承体系 |
import | 导入java的包 |
errorPage | 当前页面出错后跳转到哪个页面 |
isErrorPage | 当前页面是一个处理错误的页面,在翻译后的Servlet中会出现一个exception对象 |
-
关于错误页面的全局配置(web.xml)
<error-page> <error-code>404</error-code> <location>/404.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/500.jsp</location> </error-page>
include指令【了解】
- 页面包含(静态包含)指令,可以将一个JSP页面包含到另一个JSP页面中
<%@ include file="被包含的文件地址"%>
taglib指令【了解】
- 在jsp页面中引入标签库(JSTL标签库、Struts2标签库)
<%@ taglib uri="标签库地址" prefix="前缀"%>
5 pageContext对象
JSP页面的上下文对象
-
pageContext是一个域对象
-
void setAttribute(String name, Object value)
-
Object getAttribute(String name)
-
void removeAttrbute(String name)
-
void setAttribute(String name, Object value, int scope)【了解】
-
Object getAttribute(String name, int scope)【了解】
-
void removeAttrbute(String name, int scope)【了解】
以上3个方法中,scope的枚举值
- PageContext.APPLICATION_SCOPE
- PageContext.SESSION_SCOPE
- PageContext.REQUEST_SCOPE
- PageContext.PAGE_SCOPE
-
Object findAttribute(String name)【重点】
依次从pageContext域,request域,session域,application(ServletContext)域中获取属性,在某个域中获取后将不在向后寻找
-
6 四大作用域总结
-
pageContext
只在翻译过的service方法里面才有效【只在_jspService()方法内部】
-
request
1个用户的1次请求
-
session
1个用户的所有请求
- servletContext
所有用户的所有请求
7 案例
- 制作企业通讯录
实现
-
index.jsp
<%@ page import="com.itheima.domain.ContactsFactory" %> <%@ page import="com.itheima.domain.ContactProfile" %> <%@ page import="java.util.List" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html lang='en'> <head> <meta charset='UTF-8'> <title>Title</title> </head> <body> <table border='1px'> <tr> <th>编号</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>籍贯</th> <th>手机</th> <th>邮箱</th> </tr> <!-- 通过dao,把List读取出来 --> <% List<ContactProfile> users = ContactsFactory.produce(); %> <!-- Scriptlet编写Java代码,遍历所有的通讯录实体 --> <% for (ContactProfile profile : contacts) { %> <tr> <!-- JSP表达式输出 --> <td> <%= profile.getNo() %> </td> <td> <%= profile.getName() %> </td> <td> <%= profile.getGender().equals("male") ? "男" : "女" %> </td> <td> <%= profile.getAge() %> </td> <td> <%= profile.getBirthplace() %> </td> <td> <%= profile.getMobile() %> </td> <td> <%= profile.getEmail() %> </td> </tr> <% } %> </table> </body> </html>
8 小结
Scripting Element | Example |
---|---|
注释 | <%-- --%>【掌握】 |
指令 | <%@ %>【了解】 |
声明 | <%! 声明 %>【了解 】 |
Scriptlet | <% scriptlet %> |
表达式 | <%= 表达式 %> |
pageContext.findAttribute(name) | 从小往大 pageContext request session application |
第二部分 JSP深入 - 标签化JSP
1 标签化JSP概述
在开发JSP页面的过程中,可能会使用Scriptlet代码、表达式元素和声明元素等脚本代码,这种实现方式会使JSP页面难于阅读和维护。对于一些HTML编辑人员而言,JSP页面中的Java代码也是很难妥善处理的。
标签: 成对出现的,比如HTML标签、table标签、a标签
不是成对出现的:
<% for (ContactProfile profile : users) { %>
<% } %>
目的: 可以嵌入在JSP页面内部,减少JSP脚本的编写,替代JSP页面中的脚本元素。
2 EL表达式
2.1 EL表达式概述
Expression Language (also referred to as the EL), which provides an important mechanism for enabling the presentation layer (web pages) to communicate with the application logic (managed beans).
The EL allows page authors to use simple expressions to dynamically access data from JavaBeans components.
2.2 EL从域中取出数据
-
EL最主要的作用是获得四大域中的数据,格式
${EL表达式}
-
session.setAttribute(“name”, “zhangsan”)
-
EL获得pageContext域中的值:
${pageScope.key};
-
EL获得request域中的值:
${requestScope.key};
-
EL获得session域中的值:
${sessionScope.key};
-
EL获得application域中的值:
${applicationScope.key};
-
EL从四个域中获得某个值
${key};
同样是依次从pageContext域,request域,session域,application域中获取属性,在某个域中获取后将不在向后寻找
2.3 引用JavaBean对象属性或集合元素
引用对象属性
- ${customer.orders.socks}
- ${customer.address[“street”]}
引用集合元素
-
customer.orders 是一个List
- ${customer.orders[1]}
-
customer.orders 是一个Map<String, Object>
- ${customer.orders[“socks”]}
- ${customer.orders.socks}
2.4 EL运算符【了解】
-
算数运算
+
,-
,*
,/
anddiv
,%
andmod
,-
(取负数)
-
字符串级联
-
+=
int a =1;
a += 2;
String a = “abc”;
a += “def”;
-
-
逻辑运算
and
and&&
,or
and||
,not
and!
-
关系运算
==
andeq
,!=
andne
,<
andlt
,>
andgt
,<=
andge
,>=
andle
- 支持布尔、字符串、整型、符点数的关系运算.
-
Empty
empty
- 前置操作符,判断一个值是否为null或空
- 当empty后面的表达式为null时,empty返回true;
- 当empty后面的表达式为""时,empty返回true
-
条件运算
A ? B : C
-
Lambda 表达式->
-
赋值
=
-
分号;
2.5 小结
EL表达式的作用
-
从域中获取数据
${ pageScope.key }
${ requestScope.key }
${ sessionScope.key }
${ applicationScope.key }
${ key }
-
引用对象属性
request.setAttribute(对象名,对象)
${ 对象名.属性名 }
-
引用集合元素
- list
${ list[索引] }
- map
${ map[“键”] }
${ map.键 }
-
运算操作
empty 表达式
判断后边的表达式是否为空
null:true
“”: true
3 JSTL技术
3.1 JSTL概述:JSP标准标签库
The JavaServer Pages Standard Tag Library (JSTL) encapsulates core functionality common to many JSP applications. Instead of mixing tags from numerous vendors in your JSP applications, you use a single, standard set of tags. This standardization allows you to deploy your applications on any JSP container that supports JSTL and makes it more likely that the implementation of the tags is optimized.
JSTL has iterator and conditional tags for handling flow control, tags for manipulating XML documents, internationalization tags, tags for accessing databases using SQL, and tags for commonly used functions.
JSTL(JSP Standard Tag Library),JSP标准标签库。JSTL标准标准标签库有5个子库,但随着发展,目前常使用的是他的核心库
标签库 | 标签库的URI | 前缀 |
---|---|---|
Core | http://java.sun.com/jsp/jstl/core | c |
I18N | http://java.sun.com/jsp/jstl/fmt | fmt |
SQL | http://java.sun.com/jsp/jstl/sql | sql |
XML | http://java.sun.com/jsp/jstl/xml | x |
Functions | http://java.sun.com/jsp/jstl/functions | fn |
3.2 JSTL下载与导入
JSTL下载
http://tomcat.apache.org/download-taglibs.cgi
-
taglibs-standard-impl-1.2.5.jar
JSTL实现类库
-
taglibs-standard-spec-1.2.5.jar
JSTL标准接口
-
taglibs-standard-jstlel-1.2.5.jar
JSTL1.0标签-EL相关
-
taglibs-standard-compat-1.2.5.jar
兼容版本
JSTL导入
将taglibs-standard-impl-1.2.5.jar
和taglibs-standard-spec-1.2.5.jar
两个jar包导入到web/WEB-INF/lib
下,Add as Library
- Module Library
3.3 JSTL核心库的常用标签
Area | Function | Tags | Prefix |
---|---|---|---|
Core | Variable support | remove set | c |
Flow control | choose when otherwise forEach[重点] forTokens if[重点] | ||
URL management | import param redirect param url param | ||
Miscellaneous | catch out |
choose标签【了解】
<c:choose>
<!-- 条件判断,当满足时,进入到标签体里面 -->
<c:when test="${customer.category == ’trial’}" >
...
</c:when>
<c:when test="${customer.category == ’member’}" >
...
</c:when>
<c:when test="${customer.category == ’preferred’}" >
...
</c:when>
<!-- 当以上所有的条件都不满足时,进入到标签体里面 -->
<c:otherwise>
...
</c:otherwise>
</c:choose>
forEach标签【重点】
-
增强性for循环
for(ContactInfo contact : contacts)
<c:forEach items = "${contacts}" var = "contact"> </c:forEach>
-
基础性for循环
for(int i; i<=100; i+=2) { System.out.println(i) }
<c:forEach begin = "0" end = "100" step = "2" var = "i"> </c:forEach>
<c:forEacn
items="${collection}"
[var="varName]
[varStatus="varStatusName"]
[begin="begin"]
[end="end"]
[step="step"]>
body content
</c:forEach>
- begin, 起始序号
- end, 结束序号
- step, 步长
- varStatus支持在循环中获取相关的值,比如:
- current, 当前项
- index, 当前索引,从0开始[常用]
- count, 迭代次数,从1开始[常用]
- first, 布尔值,当前是否第1次
- last, 布尔值,当前是否是最后1次
- begin属性值
- end属性值
- step属性值
增强性for循环
注意:
- items写法,一般为 items="${}",items的属性值,通过EL表达式获取
<% for (ContactInfo contact : contacts) { } %> <c:forEach items="${contacts}" var="contact"> <tr> <td>${contact.id}</td> </tr> </c:forEach>
基础性 for循环
注意:
- 在循环当中需要使用到下标,要有var属性
- step默认值为1
<% for (int idx = 0; idx <= 100; idx++) { } %> <c:forEach begin="0" end="100" var="idx"> ${idx} </c:forEach>
if标签【重点】
<c:if test="${expression}" [var="varName"] [scope="{page|request|session|application}"]>
body evaluated if expression evaluates to true
</c:if>
4 小结
-
EL表达式
-
最核心的功能是从域对象中获取数据
${ pageScope.name }
${ requestScope }
${ sessionScope }
${ applicationScope }
${ name }
- 取JavaBean属性
${contact.property}
- 取集合元素
${list[0]}
${map.key}
${map[“spec-key”]}
-
-
JSTL技术
- forEach
-
增强性for循环
- Java
for (ContactInfo contact : request.getAttribute("contacts")) { }
- JSTL
<c:forEach items="${contacts}" var="contact"> </c:forEach>
-
基础性for循环
- Java
for (int idx = 0; idx <= 100; idx++) { }
- JSTL
<c:forEach begin="0" end="100" var="idx"> </c:forEach>
- if
- Java
if (a != b) { }
- JSTL
<c:if test="${a != b}"> </c:if>
第三部分 JavaEE模式【重点】
模式是通用问题的通用解决方案
1 模式概述
人类自从有思想以来,就在不断探寻和认识自己所生活的这个世界。从本质上说,面向过程和面向对象都是人们认识这个世界的方法;而具体的技术,则是在采用这种方法认识世界的过程中被发明、总结和归纳出来的最佳实践。对于学习者而言,掌握这些技术是重要的;掌握这些技术表示你已经继承了前人的经验积累,并且是一个捷径
– 《大象 - Thinking in UML》
每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。
– Christopher Alexander
- 模式名称
- 解决方案,给起的名字
- 问题
- 出门
- 解决方案
- 应该怎么检查、什么时候检查
- 效果
- 不会忘东西
2 Java EE经历的模式
-
Model 1 模式
JSP + JavaBean
弊端:随着业务复杂性导致JSP页面比较混乱
-
Model 2 模式
JSP + Servlet + JavaBean
优点:开发中使用各个技术擅长的方面
-
MVC
- M - Model,模型。JavaBean封装数据
- V - View,视图。JSP,页面展示
- C - Controller,控制器。Servlet,获取数据、封装数据、传递数据、指派页面
3 Java EE的三层架构
-
SSH
Struts2
Spring MVC
Hibernate
-
SSM/SSI
SpringMVC
Spring
MyBatis/iBatis
-
Web层
负责与客户端进行交互,表示页面
-
Service层
业务层,负责处理复杂的业务代码
-
DAO层
数据访问对象,只负责数据的访问(从数据库当中获取数据)
注意:三层架构,并不是每一次与特定的MVC相关。每一次里面,都可能会有完整的M、V、C
4 【扩展】面向对象
-
面向过程
更多关注的是过程
-
面向对象
更多关注的是结果
5 【扩展】做案例的思路
-
我要做什么
-
Servlet
- 接收数据
- 处理数据
- 响应数据
-
使用什么技术实现
-
数据如果涉及到保存的话,那么考虑4个域对象
-
page
Servlet的service方法内部
-
request
1个用户的1次请求
-
session
1个用户的所有请求
-
application
所有用户的所有请求
-
-
第四部分 学习目标总结
-
能够理解EL表达式
最核心的功能:从域中获取数据
${ name }
${ list[1] }
${ map.key }
${ map[“key”] } -
能够应用EL表达式获取数据
-
简单数据
${域变量名}
-
JavaBean
${域变量名.属性名}
-
Collection
${map.key名}
${map[“特殊名字”]}
${list[0]}
-
-
能够应用EL表达式执行运算
Java代码当中的绝大部分运算符都支持
${empty abc }
判断abc的值是否为空
null
为空 - true
""
为空 - true -
能够应用JSTL的标签库中的标签
<c:forEach items="${collection}" var="varName"> ${varName} </c:forEach>
<c:forEach begin="0" end="100" step="2" var="varName"> </c:forEach
<c:if test="${条件判断}"> </c:if>
-
能够描述MVC架构模式
模型视图控制器
Servlet - 控制器C
JSP - 视图V
JavaBean - 模型M