Appearance
JSP & MVC
案例目标
- 企业通讯录
分析
实现
ContactProfile.java
javapackage com.futureweaver.domain; /** * 通讯录用户信息 * */ 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
javapackage com.futureweaver.domain; import java.util.LinkedList; import java.util.List; /** * 通讯录工厂,用于批量生产通讯录用户信息,实际项目中将会采用JDBC技术从数据库读取 */ public class ContactsFactory { public static List<ContactProfile> produce() { List<ContactProfile> result = new LinkedList<>(); result.add(new ContactProfile(1, "张三", "male", 11, "广州", "134-0000-0000", "zhangsan@future-weaver.com")); result.add(new ContactProfile(2, "李四", "male", 12, "上海", "134-0000-0001", "lisi@future-weaver.com")); result.add(new ContactProfile(3, "王五", "female", 13, "广州", "134-0000-0002", "wangwu@future-weaver.com")); result.add(new ContactProfile(4, "赵六", "male", 14, "北京", "134-0000-0003", "zhaoliu@future-weaver.com")); result.add(new ContactProfile(5, "田七", "female", 15, "广州", "134-0000-0004", "tianqi@futrue-weaver.com")); return result; } }
ContactServlet.java
javapackage com.futureweaver.web; import com.futureweaver.domain.ContactProfile; import com.futureweaver.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入门
JSP概述
https://docs.oracle.com/javaee/7/tutorial/overview007.htm#BNACN
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
JSP运行原理
- Idea 部署 Tomcat 的 Web 项目目录
tex
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
Class clz = Class.forName("com.futureweaver.web.HelloServlet");
clz.newInstance();
clz.init();
- Servlet
- JSP
JSP脚本和注释
JSP脚本
jsp
<% out.write(str); %>
jsp
<%= str %>
jsp
<%!
public void method() {
}
%>
<% Scriptlet %>
【掌握】tex内部的Java代码翻译到service方法的内部
<%= 表达式 %>
【掌握】tex会被翻译成service方法内部out.print(表达式)
<%! 声明 %>
【了解】tex会被翻译成Servlet的成员的内容
JSP注释
tex
不同的注释,可见范围不同
HTML 注释
html<!-- 注释内容 -->
可见范围
JSP 源码
翻译后的 Servlet
页面显示 HTML 源码
Java 注释
java//单行注释 /* 多行注释 */ /** * Java 文档注释 **/
可见范围
JSP 源码
翻译后的 Servlet
JSP 注释【掌握】
jsp<%-- 注释内容 --%>
可见范围
- JSP 源码可见
JSP指令(3个)
JSP 的指令是指导 JSP 翻译和运行的命令,JSP 包括三大指令:
page指令【了解】
jsp
<%@ page 属性名1 = "属性值1" 属性名2 = "属性值2" %>
属性名 | 描述 |
---|---|
language | JSP脚本中可以嵌入的语言种类 |
pageEncoding | 当前JSP文件的本身编码,内部可以包含contentType response.setCharacterEncoding("utf-8") |
contentType | response.setContentType(text/html;charset=UTF-8) |
session | 是否JSP在翻译时自动创建session |
extends | 修改JSP翻译后的Servlet的继承体系 |
import | 导入java的包 |
errorPage | 当前页面出错后跳转到哪个页面 |
isErrorPage | 当前页面是一个处理错误的页面,在翻译后的Servlet中会出现一个exception对象 |
关于错误页面的全局配置(web.xml)
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 页面中
jsp
<%@ include file="被包含的文件地址"%>
taglib指令【了解】
- 在 jsp 页面中引入标签库(JSTL 标签库、Struts2 标签库)
jsp
<%@ taglib uri="标签库地址" prefix="前缀"%>
pageContext对象
tex
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)【重点】
tex一共4个域对象,作用范围从小往大: pageContext, request, session, application 先从最小的去找,如果找到了,不再往后去找了。如果找不到的话,依然向右去找。 如果都找不到的话,返回null
四大作用域总结【重点】
pageContext
作用范围: 页面域,在当前jsp页面当中
request
作用范围: 请求域,一个用户的一次请求
session
作用范围: 会话域,一个用户的所有请求
servletContext
作用范围: 上下文域,所有用户的所有请求
案例
制作企业通讯录
index.jsp
jsp<%@ page import="com.futureweaver.domain.ContactsFactory" %> <%@ page import="com.futureweaver.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>
小结
Scripting Element | Example |
---|---|
注释 | <%-- --%> |
指令【了解】 | <%@ %> |
声明【了解】 | <%! %> |
Scriptlet【重点】 | <% %> |
表达式【重点】 | <%= %> |
Object pageContext.findAttribute(name)【重点】 | 从小往大找 页面域 请求域 会话域 上下文域 |
JSP深入 - 标签化JSP
标签化JSP概述
在开发 JSP 页面的过程中,可能会使用 Scriptlet 代码、表达式元素和声明元素等脚本代码,这种实现方式会使 JSP 页面难于阅读和维护。对于一些 HTML 编辑人员而言,JSP 页面中的 Java 代码也是很难妥善处理的。
标签: 成对出现的,比如 HTML 标签、table 标签、a 标签
不是成对出现的:
jsp
<% for (ContactInfo contact : contacts) { %>
.,m.,m.,m
<% } %>
目的: 可以嵌入在 JSP 页面内部,减少 JSP 脚本的编写,替代 JSP 页面中的脚本元素。
EL表达式
<%= ... %>
EL表达式概述
https://docs.oracle.com/javaee/7/tutorial/jsf-el.htm#GJDDD
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).
https://docs.oracle.com/javaee/7/tutorial/jsf-el001.htm#BNAHQ
The EL allows page authors to use simple expressions to dynamically access data from JavaBeans components.
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};
tex同样是依次从pageContext域,request域,session域,application域中获取属性,在某个域中获取后将不在向后寻找
引用JavaBean对象属性或集合元素
引用对象属性
${customer.orders.socks}
${customer.address["street"]}
引用集合元素
customer.orders
是一个List
${customer.orders[1]}
customer.orders
是一个Map<String, Object>
${customer.orders["socks"]}
${customer.orders.socks}
EL运算符【了解】
算数运算
+
,-
,*
,/
anddiv
,%
andmod
,-
(取负数)
字符串级联
+=
str1 = "abc";
str2 = "efg";
str2 = str2 + str1;
逻辑运算
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 表达式->
赋值
=
分号;
小结
EL 表达式的作用
- 从作用域当中读取数据 ,并输出
核心语法
${}
使用方式
- 读取简单变量
${name}
- 读取 JavaBean 的属性
<% request.setAttribute("abc", contact) %>
${abc.name}
- 读取 List 元素
<% request.setAttribute("l", list); %>
${l[3]}
- 读取 Map 元素
<%request.setAttribute("m", map);%>
${m.name}
${m["name"]}
JSTL技术
JSTL概述
https://docs.oracle.com/javaee/7/tutorial/overview007.htm#BNACO
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 |
JSTL下载与导入
JSTL下载
https://projects.eclipse.org/projects/ee4j.jstl
https://mvnrepository.com/artifact/org.glassfish.web/jakarta.servlet.jsp.jstl
https://mvnrepository.com/artifact/jakarta.servlet.jsp.jstl/jakarta.servlet.jsp.jstl-api
jakarta.servlet.jsp.jstl-api-3.0.0.jar
texJSTL标准接口
jakarta.servlet.jsp.jstl-3.0.1.jar
texJSTL实现类库
JSTL导入
将jakarta.servlet.jsp.jstl-api-3.0.0.jar
和jakarta.servlet.jsp.jstl-3.0.1.jar
两个 jar 包导入到web/WEB-INF/lib
下,Add as Library
- Module Library
JSTL常用标签
https://docs.oracle.com/javaee/5/tutorial/doc/bnakh.html
Core Tag Library
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 |
XML Tag Library
Area | Function | Tags | Prefix |
---|---|---|---|
XML | Core | out parse set | x |
Flow control | choose when otherwise forEach if | ||
Transformation | transform param |
Internationalization Tag Library
Area | Function | Tags | Prefix |
---|---|---|---|
I18N | Setting Locale | setLocale requestEncoding | fmt |
Messaging | bundle message param setBundle | ||
Number and Date Formatting | formatNumber formatDate parseDate parseNumber setTimeZone timeZone |
SQL Tag Library
Area | Function | Tags | Prefix |
---|---|---|---|
Database | Setting the data source | setDateSource | sql |
SQL | query dateParam param transaction update dateParam param |
JSTL Functions
Area | Function | Tags | Prefix |
---|---|---|---|
Functions | Collection length | length | fn |
String manipulation | toUpperCase, toLowerCase substring, substringAfter, substringBefore trim replace indexOf, startsWith, endsWith, contains, containsIgnoreCase split, join escapeXml |
choose标签【了解】
jsp
<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标签【重点】
java
for (ContactInfo contact : contacts) {
contact....
}
// 在JSTL的forEach标签当中
// contacts是使用items标签属性来表示
// contact是使用var标签属性来表示
jsp
<c:forEach items="${contacts}" var="contact">
${contact}
<%-- 因为var标签属性,将这个变量,放到了作用域当中 --%>
</c:forEach>
java
for (int index = 0; index <= 100; index = index + 2) {
sout(index);
}
jsp
<c:forEach begin="0" end="100" step="2" var="index">
${index}<br/>
</c:forEach>
tex
<c:forEach
items="${collection}"
[var="varName"]
[varStatus="varStatusName"]
[begin="begin"]
[end="end"]
[step="step"]>
body content
</c:forEach>
begin, 起始序号
end, 结束序号
step, 步长
varStatus 支持在循环中获取相关的值,比如:
<c:forEach begin="0" end="100" step="2" varStatus="varible"> ${variable.index} ${varible.count} ${variable.index} </c:forEach>
- current, 当前项
- index, 当前索引,从 0 开始[常用]
- count, 迭代次数,从 1 开始[常用]
- first, 布尔值,当前是否第 1 次
- last, 布尔值,当前是否是最后 1 次
- begin 属性值
- end 属性值
- step 属性值
- 增强性for循环
注意:
- items写法,一般为 items="${}",items的属性值,通过EL表达式获取
javafor (ContactInfo contact: contacts) { contact.getId(); }
jsp<c:forEach items="${contacts}" var="contact"> ${contact.id} </c:forEach>
- 基础性 for循环
注意:
- 在循环当中需要使用到下标,要有var属性
- step默认值为1
javafor (int idx = 0; idx <= 100; idx += 2) { idx; }
jsp<c:forEach begin="0" end="100" step="2" var="idx"> ${idx} </c:forEach>
if标签【重点】
jsp
<c:if test="${expression}" [var="varName"] [scope="{page|request|session|application}"]>
body evaluated if expression evaluates to true
</c:if>
使用 if 及它的标签属性,完成 if-else 的需求
jsp
<c:if test="${empty a}" var="cond">
${a}
</c:if>
<c:if test="${!cond}">
</c:if>
小结
EL 表达式
- 作用(唯一的作用): 从域当中取数据,并且展示
- 使用方式:
- 简单对象
${name}
- JavaBean 属性
${bean.name}
- List 元素
${list[0]}
- Map 元素
${map.key}
${map["key"]}
- 简单对象
JSTL 技术
JSP标准标签库
forEach
增强性 for 循环
jsp<c:forEach items="${contacts}" var="contact"> ${contact.name}<br/> </c:forEach>
基础性 for 循环
jsp<c:forEach begin="0" end="100" step="3" var="abc"> ${abc}<br/> </c:forEach>
javafor (int abc=0; abc<=100; abc+=3) { out.write(abc); out.write("<br/>") }
javafor (int abc=0; abc<=100; abc++) { if (条件1 && 条件2) { // 这个数字是水仙花数 } }
if
jsp<c:if test="${判断语句}"> <%-- 判断成功之后输出的内容 --%> </c:if>
JavaEE模式【重点】
《GoF 设计模式》
Gang of Four
23 种设计模式
模式概述
人类自从有思想以来,就在不断探寻和认识自己所生活的这个世界。从本质上说,面向过程和面向对象都是人们认识这个世界的方法;而具体的技术,则是在采用这种方法认识世界的过程中被发明、总结和归纳出来的最佳实践。对于学习者而言,掌握这些技术是重要的;掌握这些技术表示你已经继承了前人的经验积累,并且是一个捷径
– 《大象 - Thinking in UML》
每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。
– Christopher Alexander
- 模式名称
- 解决方案,给起的名字
- 问题
- 出门
- 解决方案
- 应该怎么检查、什么时候检查
- 效果
- 不会忘东西
Java EE经历的模式
注意: MVC是架构模式,并不是设计模式
Model 1 模式
JSP + JavaBean
弊端:随着业务复杂性导致 JSP 页面比较混乱
Model 2 模式
JSP + Servlet + JavaBean
优点:开发中使用各个技术擅长的方面
MVC
- M - Model,模型。JavaBean 封装数据
- V - View,视图。JSP,页面展示
- C - Controller,控制器。Servlet,获取数据、封装数据、传递数据、指派页面
Java EE的三层架构
SSH
Struts2
Spring
Hibernate
SSM/SSI
SpringMVC
Spring
MyBatis/iBatis
Web 层
tex负责与客户端进行交互,表示页面
Service 层
tex业务层,负责处理复杂的业务代码
DAO 层
tex数据访问对象,只负责数据的访问(从数据库当中获取数据)
注意:三层架构,并不是每一次与特定的 MVC 相关。每一次里面,都可能会有完整的 M、V、C
【扩展】面向对象
面向过程
更多关注的是过程
面向对象
更多关注的是结果
制作企业通讯录案例
面向过程的思路:
- 接收用户的请求
- mapper 需要准备 SqlSessionFactoryBuilder
- 需要准备 SqlSessionFacotry
- 需要准备 session
- 需要准备 mapper
- 调用 mapper 获取
- 需要拿到一个 List
- 遍历 list
- 在循环体当中,输出内容
面向对象的思路
- 表示层-servlet
- 接收数据
- 通过 service,获取 list
- 将 list 放到作用域当中
- 转发到 jsp
- 业务层-service
- 从 mapper 当中,获取 list
- 返回 list
- 整合层-mapper
- 准备 builder
- 准备 factory
- 准备 session
- 返回 mapper
- 表示层-jsp
- 从作用域当中,获取集合
- 遍历集合,输出
【扩展】做案例的思路
我要做什么
Servlet
- 接收数据
- 处理数据
- 响应数据
使用什么技术实现
数据如果涉及到保存的话,那么考虑 4 个域对象
page
Servlet的service方法内部
request
1个用户的1次请求
session
1个用户的所有请求
application
所有用户的所有请求
资源跳转
- 优先考虑重定向,如果重定向搞不定的话,使用转发
- 重定向与转发的 3 个特点以及区别
学习目标总结
能够理解 EL 表达式
能够应用 EL 表达式获取数据
能够应用 EL 表达式执行运算
能够应用 JSTL 的标签库中的标签
能够描述 MVC 架构模式
能够掌握三层架构