3_JSP
一. 引言
1.1 现有问题
- 在之前学习Servlet时, 服务器通过Servlet响应客户端页面, 有什么不足之处?
- 开发方式麻烦: 继承父类, 覆盖方法, 配置web.xml或注解
- 代码修改麻烦: 重新编译, 部署, 重启服务
- 显示方式麻烦: 获取流, 使用println("")逐行打印
- 协同开发麻烦: UI负责美化页面, 程序员负责编写代码. UI不懂java, 程序员又不能将所有前端页面的内容通过流输出
二. JSP (Java Server Pages)
2.1 概念
- 简化的Servlet设计, 在HTML标签中嵌套Java代码, 用来高效开发Web应用的动态网页
2.2 作用
- 替换显示页面部分的Servlet(使用*.jsp文件替换XxxJSP.java)
三. JSP开发[重点]
3.1 创建JSP
- 在Web目录下新建*.jsp文件 (与WEB-INF平级)
3.1.1 JSP编写Java代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>This is my first page!</title>
</head>
<body>
Now:<%=new java.util.Date() %>
</body>
</html>
- 使用<%=%>标签编写Java代码在页面中打印当前系统时间
3.1.2 访问JSP
- 在浏览器中输入http://ip:port/项目路径/资源名称
3.2 JSP与Servlet
- 关系
- JSP文件在容器中会转换成Servlet执行
- JSP是对Servlet的一种高级封装, 本质还是Servlet
- 区别
- 与Servlet相比LJSP可以很方便的编写或者修改HTML网页而不用去面对大量的println语句
Servlet
- 编码:
- 继承HttpServlet + 注解或配置web.xml
- 修改:
- 重新部署, 重启服务器
- 访问:
- http://ip:port/apps/url-pattern
- 标签:
- printWriter.println("< html>");
JSP
- 编码
- HTML中直接编写Java代码
- 修改:
- 刷新页面
- 访问:
- http://ip:port/apps/路径+*.jsp
- 标签:
- 直接编写HTML标签
3.3 JSP实现原理
- Tomcat会将xxx.jsp转换成Java代码, 进而编译成.class文件运行, 最终将运行结果通过response响应给客户端
3.3.1 JSP.java源文件存放目录
- 使用IDEA开发工具, Tomcat编译后的JSP文件(Xxx_jsp.class和Xxx_jsp.java)的存放地点:
- C:\用户名\账户名\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\项目名称\work\Catalina\localhost\应用上下文\org\apache\jsp
- AppData或许需要查看隐藏的项目
- 可以在Tomcat启动后在控制台里找到路径
四. JSP与HTML集成开发
4.1 脚本
- 脚本可以编写Java语句, 变量, 方法或表达式
4.1.1 普通脚本
- 语法: <% Java代码 &>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>脚本的使用</title>
</head>
<body>
<%
//jsp中, 使用小脚本嵌入Java代码
int a = 10;//普通脚本定义的是局部变量
System.out.println(a);//打印内容在控制台
out.println(a);//打印内容在客户端页面
%>
</body>
</html>
- 经验: 普通脚本可以使用所有Java语法, 除了定义函数
- 注意: 脚本与脚本之间不可嵌套, 脚本与HTML标签不可嵌套
4.1.2 声明脚本
- 语法: <%! 定义变量., 函数 %>
<%!
int b = 20;//声明脚本定义的是全局变量
public void test() {//定义一个无返回值的方法
System.out.println("你好");
}
public int test1() {//定义一个有返回值的方法
return 100;
}
%>
- 注意: 声明脚本声明的变量是全局变量
- 声明脚本的内容必须在普通脚本<% % >中调用
- 如果声明脚本中的函数具有返回值, 可以使用输出脚本调用<%= %>
4.1.3 输出脚本
- 语法: <%= Java表达式 %>
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>脚本的使用</title>
</head>
<body>
<%=test1()%>
<%="今天天气很好!"%>
<%=666%>
<%=new Date()%>
</body>
</html>
- 经验: 输出脚本可以输出带有返回值的函数
- 注意: 输出脚本中不能加分号;
4.2 JSP注释
- JSP注释有两个作用: 为脚本代码作注释以及HTML内容注释
4.2.1 语法规则
- <%--- 注释 ---%>
- JSP注释, 注释内容不会被发送至浏览器甚至不会被编译
- <%!--- 注释 ---%>
- HTML注释, 通过浏览器查看网页源代码时可以看见注释内容
4.2.2 注释
<%-- JSP注释在网页中不会被显示 --%>
<%!-- HTML注释在网页源代码中会显示 --%>
4.3 JSP指令
- JSP指令用来设置与整个JSP页面相关的属性
- <%@ page ...%>: 定义页面的依赖属性, 比如脚本语言, error页面, 缓存需求等
- <%@ include ...%>: 包含其他文件
- <%@ taglib ...%>: 引入标签库的定义, 可以是自定义标签
4.3.1 page指令
- 语法: <%@ page attribute1="value1" attribute2="value2"%>
- page指令为容器提供当前页面的使用说明, 一个JSP页面可以包含多个page指令
- contentType: 指定当前JSP页面的MIME类型和字符编码格式
- errorPage: 指定当JSP页面发生异常时需要转向的错误处理页面
- isErrorPage: 指定当前页面是否可以作为另一个JSP页面的错误处理页面
- import: 导入要使用的Java类
- language: 定义JSP页面所用的脚本语言, 默认是Java
- session: 指定JSP页面是否使用session, 默认为true立即创建, false为使用时创建
- pageEncoding: 指定JSP页面的解码格式
4.3.2 include指令
- 语法: <%@ include file = "被包含的JSP路径"%>
- 通过include指令来包含其他文件
- 被包含的文件可以是JSP文件, HTML文件或文本文件. 包含的文件就好像是当前JSP文件的一部分, 会被同时编译执行(静态包含)
<%@include file="header.jsp"%>
...
...
<%@include file="footer.jsp"%>
- 注意: 可能会有重名的冲突问题, 不建议使用
4.3.3 taglib指令
- 语法: <%@ taglib url = "外部标签库路径" prefix = "前缀"%>
- 引入JSP的标准标签库
<%@ taglib url="http://java.sun.com/jsp/jstl/core" prefix="c" %>
4.4 动作标签
- 语法: <jsp: action_name attribute="value" />
- 动作标签指的是JSP页面在运行期间的命令
4.4.1 include
- 语法: <jsp: include page = "相对 URL 地址" />
- <jsp: include >动作元素会将外部文件输出结果包含在JSP中 (动态包含)
- page: 包含在页面中的相对URL地址
<jsp:include page="index.jsp"/>
- 注意:前面已经介绍过include指令, 它是将外部文件的输出代码复制到了当前JSP文件中, 而这里的jsp:include动作不同, 是将外部文件的输出结果引入到了当前JSP文件中
4.4.2 useBean
- 语法: <jsp: useBean id="name" class="package.className" />
- jsp:useBean 动作用来加载一个将在JSP页面中使用的JavaBean
<jsp:useBean id="user" class="com.dz.entity.User" />
- 在类载入后, 我们可以通过jsp:setProperty和jsp:getProperty动作来修改和获取bean的属性
4.4.3 setProperty
- 可以在jsp:useBean元素之后使用jsp:setProperty进行属性的赋值
- name: name属性是必需的. 它表示要设置属性的是哪个Bean
- property: property属性是必需的. 它表示要设置哪个属性
- value: value属性是可选的. 该属性用来指定Bean属性的值
<jsp:useBean id="user" class="com.dz.entity.User" />
<jsp:setProperty name="user" property="name" value="mars">
4.4.4 getProperty
- jsp:getProperty动作提取指定Bean属性的值, 转换成字符串, 然后输出
- name: 要检索的Bean属性名称. Bean必须已定义
- property: 表示要提取Bean属性的值
<jsp:useBean id="user" class="com.dz.entity.User" />
<jsp:setProperty name="user" property="name" value="mars" />
<jsp:getProperty name="user" property="name" />
4.4.5 forward
- 语法: <jsp: forward page="相对 URL 地址" />
- jsp:forward动作把请求转到另外的页面
- page: page属性包含的是一个相对URL
<jsp:forward page="index.jsp" />
4.4.6 param
- 语法: <jsp: param name="" value="" />
- 在转发动作内部使用. 做参数传递
<jsp:forward page="index.jsp">
<!--- http请求参数传递 --->
<jsp:param name="sex" value="man" />
</jsp:forward>
- 获取参数的值: <%String result = request.getParameter("sex");%>
4.5 内置对象
由JSP自动创建的对象, 可以直接使用
对象名 类型 说明
request javax.servlet.http.HttpServletRequest
response javax.servlet.http.HttpServletResponse
session javax.servlet.http.HttpSession 由session="true"开关
**application ** javax.servlet.ServletContext
config javax.servlet.ServletConfig
exception java.lang.Throwable 由isErrorPage="false"开关
out javax.servlet.jsp.JspWriter
**pageContext ** javax.servlet.jsp.PageContext
page java.lang.Object当前对象this 当前servlet实例
4.5.1 四大域对象
- JSP有四大作用域对象, 存储数据和获取数据的方式一样, 不同的是取值的范围有差别
- pageContext: 当前JSP页面范围
- request: 一次请求有效
- session: 一次会话有效(关闭浏览器失效)
- application: 整个Web应用有效(服务器重启或关闭失效)
4.5.2 pageContext对象
- pageContext对象是javax.servlet.jsp.PageContext类的实例, 拥有作用域, 用来代表整个JSP页面
- 当前页面的作用域对象, 一旦页面跳转则失效
- 通过setAttribute("name",value);存储值
- 通过getAttribute("name");获取值
- 用于获取其他8个内置对象或者操作其他对象的作用域
<%
pageContext.setAttribute("name",value);//当前页面作用域有效
%>
4.5.3 pageContext获取其他内置对象
<%
pageContext.getRequest();//返回request内置对象
pageContext.getResponse();//返回response内置对象
pageContext.getSession();//返回session内置对象
pageContext.getServletContext();//返回application内置对象
pageContext.getOut();//返回out内置对象
pageContext.getException();//返回exception内置对象
pageContext.getPage();//返回page内置对象
pageContext.getServletConfig();//返回config内置对象
%>
4.5.4 pageContext操作其他内置对象的作用域
- pageContext对象可以操作其他作用域存储和获取
<%
/*操作其他作用域存储*/
pageContext.setAttribute("page", "123", PageContext.PAGE_SCOPE);//当前页面作用域
pageContext.setAttribute("req","aaa", PageContext.REQUEST_SCOPE);//request作用域
pageContext.setAttribute("session","bbb", PageContext.SESSION_SCOPE);//session作用域
pageContext.setAttribute("application","ccc", PageContext.APPLICATION_SCOPE);//application作用域
/*操作其他作用域获取*/
String value = (String) pageContext.getAttribute("page");//当前页面作用域
String value1 = (String) request.getAttribute("req");//request作用域
String value2 = (String) session.getAttribute("session");//session作用域
String value3 = (String) application.getAttribute("application");//application作用域
String value4 = (String) pageContext.findAttribute("req");//从pageContext, request, session, application四个作用域中依次查找
%>
4.6 整合
- 将EmpProject项目的所有显示页面JSP的Servlet替换为JSP页面, 使用脚本进行显示
4.6.1 showAllEmp.jsp
<%@ page import="com.dz.emp.entity.Emp" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>查询所有员工页面</title>
</head>
<body>
<form action='/EmpProject/manager/safe/showInsertEmp.jsp'>
<p><input type='submit' value='新增'></p>
</form>
<table border='1'>
<tr>
<td>编号</td>
<td>姓名</td>
<td>工资</td>
<td>年龄</td>
<td colspan='2'>操作</td>
</tr>
<%
List<Emp> empList = (List<Emp>) request.getAttribute("empList");//从request中拿数据
for (Emp emp : empList) {
%>
<tr>
<td><%=emp.getId()%></td>
<td><%=emp.getName()%></td>
<td><%=emp.getSalary()%></td>
<td><%=emp.getAge()%></td>
<td><a href="<%=request.getContextPath()+"/manager/safe/removeEmpController?id="+emp.getId()%>">删除</a></td>
<td><a href="<%=request.getContextPath()+"/manager/safe/showEmpController?id="+emp.getId()%>">修改</a></td>
</tr>
<%
}
%>
</table>
</body>
</html>
4.6.2 showInsertEmp.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>新增员工信息页面</title>
</head>
<body>
<form action='/EmpProject/manager/safe/insertEmpController' method='post'>
<p>姓名:<input type='text' name='name'></p>
<p>工资:<input type='text' name='salary'></p>
<p>年龄:<input type='text' name='age'></p>
<p><input type='submit' value='提交'></p>
</form>
</body>
</html>
4.6.3 showUpdateEmp.jsp
<%@ page import="com.dz.emp.entity.Emp" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>修改员工信息页面</title>
</head>
<body>
<%
Emp emp = (Emp) request.getAttribute("emp");
%>
<form action='/EmpProject/manager/safe/updateEmpController' method='post'>
<p>编号:<input type='text' name='id' value=<%=emp.getId()%> readonly></p>
<p>姓名:<input type='text' name='name' value=<%=emp.getName()%>></p>
<p>工资:<input type='text' name='salary' value=<%=emp.getSalary()%>></p>
<p>年龄:<input type='text' name='age' value=<%=emp.getAge()%>></p>
<p><input type='submit' value='修改'></p>
</form>
</body>
</html>
五. El表达式 (Expression Language)
5.1 概念
- EL使JSP写起来更简单, 简洁, 主要用于获取作用域中的数据
5.2 作用
- 用于替换作用域对象.getAttribute("name");
5.3 EL的应用 (获取基本类型, 字符串)
- ${scope.name} 获取具体某个作用域中的数据
- ${name} 获取作用域中的数据, 逐级查找(pageContext, request, session, application) 注意: 使用此方法时要确保name在作用域中是唯一的
5.3.1 EL应用案例
<body>
<%
request.setAttribute("key1","value1");
session.setAttribute("key2", "value2");
application.setAttribute("key3", "value3");
%>
<%--通过作用域对象获取数据--%>
<h1><%=request.getAttribute("key1")%></h1>
<h1><%=session.getAttribute("key2")%></h1>
<h1><%=application.getAttribute("key3")%></h1>
<hr/>
<%--通过EL表达式获取数据--%>
<h1>${requestScope.key1}</h1>
<h1>${sessionScope.key2}</h1>
<h1>${applicationScope.key3}</h1>
<hr/>
<h1>${key1}</h1>
<h1>${key2}</h1>
<h1>${key3}</h1>
</body>
5.3.2 EL和JSP脚本的区别
- <%=request.getAttribute()%>没有找到返回null
- ${requestScope.name}没有找到返回""
5.4 EL的应用 (获取引用类型)
- 使用EL获取作用域中的对象调用属性时, 只能访问对象的get方法, 必须遵守命名规范定义
<%@ page import="com.dz.entity.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>El获取对象</title>
</head>
<body>
<%
User user = new User("mars","123");
request.setAttribute("user",user);
%>
${user}<br>
${user.username}<br>
${user.password}<br>
</body>
</html>
5.5 EL的应用 (获取数组, 集合的元素)
- EL可以获取Array, List, Map 中的元素, Set由于无下标, 无法直接访问元素, 后续可遍历
<%
int[] array = new int[]{1,2,3,4,5};
request.setAttribute("array",array);
List<String> nums = new ArrayList<>();
nums.add("A");
nums.add("B");
nums.add("C");
request.setAttribute("nums",nums);
Map<String,String> maps = new HashMap<>();
maps.put("CN","中国");
maps.put("US","美国");
maps.put("UK","英国");
request.setAttribute("maps",maps);
%>
<%--EL访问数据--%>
${array[0]}<br>
${array[1]}<br>
${array[2]}<br>
<hr>
${nums[0]}<br>
${nums[1]}<br>
${nums.get(2)}<br>
<hr>
${maps["CN"]}<br>
${maps["US"]}<br>
${maps.UK}<br>
5.6 EL的运算符
操作符
.
- 访问一个Bean属性或者一个映射条目
[]
- 访问一个数组或者链表的元素
加
- 减
乘
/ or div
- 除
% or mod
- 取模
== or eq
- 测试是否相等
!= or ne
- 测试是否不等
< or lt
- 测试是否小于
(>) or gt
- 测试是否大于
<= or le
- 测试是否小于等于
(>=) or ge
- 测试是否大于等于
&& or and
- 测试逻辑与
|| or or
- 测试逻辑或
! or not
- 测试取反
empty
- 测试是否空值
5.6.1 EL表达式执行运算
<%
request.setAttribute("nums",100);
request.setAttribute("n","");
request.setAttribute("m",null);
%>
<h1>算数运算符</h1>
<h1>${nums + 2}</h1>
<h1>${nums - 2}</h1>
<h1>${nums * 2}</h1>
<h1>${nums div 2}</h1>
<h1>${nums mod 2}</h1>
<hr>
<h1>关系运算符</h1>
<h1>${nums eq 101}</h1><%-- = --%>
<h1>${nums ne 101}</h1><%-- != --%>
<h1>${nums lt 101}</h1><%-- < --%>
<h1>${nums gt 101}</h1><%-- > --%>
<h1>${nums le 101}</h1><%-- <= --%>
<h1>${nums ge 101}</h1><%-- >= --%>
<hr>
<h1>逻辑运算符</h1>
<h1>${nums > 100 and nums < 200}</h1>
<h1>${nums > 100 or nums < 200}</h1>
<h1>${not(nums > 100)}</h1>
<hr>
<h1>empty运算符</h1>
<h1>${empty n}</h1>
<h1>${empty m}</h1>
5.6.2 empty关键字
<%
request.setAttribute("n","");
request.setAttribute("m",null);
%>
<%--empty关键字 只要内容为空 就返回true--%>
<h1>empty运算符</h1>
<h1>${empty n}</h1>
<h1>${empty m}</h1>
5.7 隐式对象
- EL表达式语言定义了11个隐式对象
- pageScope
- page作用域
- requestScope
- request作用域
- sessionScope
- session作用域
- applicationScope
- application作用域
- param
- Request对象的参数, 字符串
- paramValues
- Request对象的参数, 字符串
- header
- HTTP信息头, 字符串
- headerValues
- HTTP信息头, 字符串集合
- initParam
- 上下文初始化参数
- cookie
- Cookie值
- pageContext
- 当前页面的pageContext
5.7.1 获得应用上下文
<%=request.getContextPath()%>
${pageContext.request.contextPath}
5.7.2 获取Cookie对象
<h1>${cookie.username}</h1><%--获取名为username的cookie对象--%>
<h1>${cookie.password}</h1><%--获取名为password的cookie对象--%>
<h1>${cookie.username.value}</h1><%--获取名为username的cookie对象的value值--%>
<h1>${cookie.password.value}</h1><%--获取名为password的cookie对象的value值--%>
六. JSTL标准标签库
6.1 现有问题
- EL主要是用于作用域获取数据, 虽然可以做运算判断, 但是得到的都是一个结果, 做展示
- EL不存在流程控制, 比如判断
- EL对于集合只能做单点访问, 不能实现遍历操作, 比如循环
6.2 什么是JSTL
- JSTL: 全称Java Server Pages Standard Tag Library
- JSP标准标签库(JSTL) 是一个JSP标签集合
6.3 JSTL的作用
- 可对EL获取到的数据进行逻辑操作
- 与EL合作完成数据的展示
6.4 JSTL使用
- 导入两个jar文件: standard.jar 和 jstl.jar 文件拷贝到 /WEB-INF/lib/ 下
- 在JSP页面引入标签库<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
6.5 核心标签
6.5.1 条件标签if判断
- 语法: <c:if test="条件">< /c:if>
<%
request.setAttribute("username","dz");
%>
${username}
<%-- test属性中是条件, 但是条件需要使用EL表达式来书写 --%>
<c:if test="${username eq 'dz'}">
<h1>欢迎您, ${username}</h1>
</c:if>
<c:if test="${username ne 'dz'}">
<h1>请您重新登陆!</h1>
</c:if>
6.5.2 多条件choose判断
语法: < c:choose>
<c:when test="条件1">结果1< /c:when>
<c:when test="条件2">结果2< /c:when>
<c:when test="条件3">结果3< /c:when>
< c:otherwise>结果4< /c:otherwise>
< /c:choose>
<%
request.setAttribute("age",18);
%>
<c:choose>
<c:when test="${age < 18}"><h1>少年</h1></c:when>
<c:when test="${age >= 18 and age < 30}"><h1>中年</h1></c:when>
<c:when test="${age >= 30 and age < 50}"><h1>中年</h1></c:when>
<c:otherwise><h1>老年</h1></c:otherwise>
</c:choose>
6.5.3 迭代foreach标签
语法
<c:forEach
var="变量名"
items="集合"
begin="起始下标"
end="结束下标"
step="间隔长度"
varstatus="遍历状态">
</c:forEach>
<%
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
request.setAttribute("list",list);
%>
<%-- varStatus: 变量状态: 遍历出每一项内容的状态
first: 是否是第一行
last: 是否是最后一行
count: 当前行数
index: 当前元素的下标
--%>
<%-- var: 遍历出的每一项使用变量先存储
items: 集合(使用EL表达式)
--%>
<c:forEach var="v" items="${list}" begin="0" end="4" step="1" varStatus="vs">
<h1>${v} ${vs.first} ${vs.last} ${vs.count} ${vs.index}</h1>
</c:forEach>
6.5.4 url标签
- 在Cookie禁用的情况下, 通过重写URL拼接JSESSION来传递ID值, 便于下一次访问时仍可查到上一次的Session对象
<%--重写URL,拼接jsessionid(旧方法)--%>
<%
String newURL = response.encodeRedirectURL(request.getContextPath()+"/jstl/jstl1.jsp");
%>
<%=newURL%>
<a href="<%=response.encodeRedirectURL(request.getContextPath()+"/jstl/jstl1.jsp")%>">跳转</a><br>
<%--重写URL,拼接jsessionid(新方法,使用url标签)--%>
<c:url context='${pageContext.request.contextPath}' value='/jstl/jstl1.jsp'></c:url>
<a href="<c:url context='${pageContext.request.contextPath}' value='/jstl/jstl1.jsp'></c:url>">跳转2</a>
<%--在form表单的action中嵌套动态路径--%>
<form action="<c:url context='${pageContext.request.contextPath}' value='/jstl/jstl1.jsp'></c:url>">
<input type="submit" value="提交">
</form>
- 经验: 所有涉及到页面跳转或者重定向跳转时, 都应该使用URL重写
6.6 整合
- 将现有的EmpProject项目进行整合, 使用EL+JSTL替换脚本代码
6.6.1 showAllEmp.jsp
<%@ page import="com.dz.emp.entity.Emp" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>查询所有员工页面</title>
</head>
<body>
<form action="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showInsertEmp.jsp'></c:url>">
<p><input type='submit' value='新增'></p>
</form>
<table border='1'>
<tr>
<td>编号</td>
<td>姓名</td>
<td>工资</td>
<td>年龄</td>
<td colspan='2'>操作</td>
</tr>
<c:forEach var="emp" items="${empList}">
<tr>
<td>${emp.id}</td>
<td>${emp.name}</td>
<td>${emp.salary}</td>
<td>${emp.age}</td>
<td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/removeEmpController?id=${emp.id}'></c:url>">删除</a></td>
<td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showEmpController?id=${emp.id}'></c:url>">修改</a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
6.6.2 showUpdateEmpInfo.jsp
<%@ page import="com.dz.emp.entity.Emp" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>修改员工信息页面</title>
</head>
<body>
<form action="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/updateEmpController'></c:url>" method='post'>
<p>编号:<input type='text' name='id' value=${emp.id} readonly></p>
<p>姓名:<input type='text' name='name' value=${emp.name}></p>
<p>工资:<input type='text' name='salary' value=${emp.salary}></p>
<p>年龄:<input type='text' name='age' value=${emp.age}></p>
<p><input type='submit' value='修改'></p>
</form>
</body>
</html>
6.6.3 showInsertEmp.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>新增员工信息页面</title>
</head>
<body> <form action='<c:url context="${pageContext.request.contextPath}" value="/manager/safe/insertEmpController"></c:url>' method='post'>
<p>姓名:<input type='text' name='name'></p>
<p>工资:<input type='text' name='salary'></p>
<p>年龄:<input type='text' name='age'></p>
<p><input type='submit' value='提交'></p>
</form></body>
</html>
七. MVC框架(Model-View-Controller)
7.1 MVC概念
- MVC又称为编程模式, 是一种软件设计思想, 将数据操作, 页面展示, 业务逻辑分为三个层级(模块), 独立完成, 相互调用
- 模型层(Model)
- 视图(View)
- 控制器(Controller)
7.2 MVC模式详解
- MVC并不是Java独有的, 现在几乎所有的B/S架构都采用MVC模式
- 视图View层:
- 视图即是用户看到并与之交互的界面, 比如HTML(静态资源), JSP(动态资源) 等等
- 控制器Controller层:
- 控制器即是控制请求的处理逻辑, 对请求进行处理, 负责流程跳转(转发和重定向)
- 模型Model层(Service+DAO+Entity):
- 对客观世界的一种代表和模拟(业务模拟, 对象模拟)
- 视图View层:
7.3 优点
- 低耦合性: 模块与模块之间的关联性不强, 不与某一种具体实现产生密不可分的关联性
- 高维护性: 基于低耦合性, 可做到不同层级的功能模块灵活更换, 插拔
- 高重用性: 相同的数据库操作, 可以服务于不同的业务处理, 将数据作为独立模块, 提高重用性
7.4 MVC在框架中应用
- MVC模式被广泛用于Java的各种框架中, 比如Struct2, SpringMVC等都用到了这种思想
7.5 三层架构与MVC
7.5.1 三层架构
- View层 (表示|界面层)、Service层 (业务逻辑层)、DAO层(数据访问层)
- 表示层(UI, Main)
- 职责:
- 收集用户输入数据
- 调用业务逻辑层, 完成业务方法
- 展示数据或展示操作结果
- 职责:
- 业务逻辑层(service)
- 职责:
- 开启事务
- 调用DAO层
- 处理数据
- 提交或回滚
- 职责:
- 数据访问层(DAO)
- 职责:
- 查询相关业务逻辑的数据
- 根据相关业务逻辑修改的数据
- 职责:
7.5.2 MVC与三层架构的区别
- MVC强调的是视图和业务代码的分离, 严格的说MVC其实关注的是Web层, View就是单独的页面, 如JSP, HTML等, 不负责业务处理, 只负责数据的展示. 而数据封装到Model里, 由Controller负责在View和Model之间传递, MVC强调业务和视图分离
- 三层架构是 数据访问层(DAO), 业务逻辑层(Service), 表示层(View), 指的是代码之间的解耦, 方便维护和复用
八. 分页
8.1 概念
- 分页是Web应用程序非常重要的一个技术. 数据库中的数据可能是成千上万的, 不可能把这么多的数据一次显示在浏览器上面, 一般根据每行数据在页面上所占的空间设置每页显示若干行, 比如一般20行是一个比较理想的显示状态
8.2 分页实现思路
- 对于海量的数据查询, 需要多少就取多少, 显然是最佳的解决方案, 假如某个表中有200万条记录, 第一页取前20条, 第二页取21~40条记录
select * from 表名 limit 0,20;//第一页
select * from 表名 limit 20,20;//第二页
select * from 表名 limit 40,20;//第三页
8.3 分页代码实现
- 步骤
- 确定每页显示的数据数量
- 确定分页显示所需的总页数
- 编写SQL查询语句, 实现数据查询
- 在JSP页面中进行分页显示设置
8.3.1 数据库准备
CREATE TABLE emp(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20) NOT NULL,
salary DOUBLE NOT NULL,
age INT NOT NULL
)CHARSET=utf8;
#向数据库中添加100条数据
INSERT INTO emp(NAME,salary,age) VALUES('dz1',1000,18);
......(此处省略,请自行插入数据)
8.3.2 数据库配置文件db.properties
#<!-- 连接设置 -->
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/emp?useUnicode=true&characterEncoding=UTF-8
username=root
password=root
#<!-- 初始化连接 -->
initialSize=10
#<!-- 最大连接数量 -->
maxActive=50
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 60000毫秒/1000等于60秒 -->
maxWait=5000
8.3.3 PageBean类
- 分页数据所需要的实体类! 其包含页码, 页大小, 总条数, 总页数, 起始行
package com.dz.emp.entity;
public class Page {
private Integer pageIndex;//页码, 第几页
private Integer pageSize;//页大小, 每页显示多少行数据
private Integer totalCounts;//数据的总行数, 一共有多少条数据
private Integer totalPages;//总页数, 数据一共可以分为多少页
private Integer startRows;//起始行, 用户从第几行开始查数据
//单参构造方法,参数为 页码pageIndex,内部调用两参构造方法,且把 页大小pageSize 的值固定为5
public Page(Integer pageIndex) {
this(pageIndex,5);
}
//两参构造方法,参数为 页码pageIndex, 页大小pageSize,并且设置 起始行startRows 为(pageIndex-1)*pageSize
public Page(Integer pageIndex, Integer pageSize) {
this.pageIndex = pageIndex;
this.pageSize = pageSize;
this.setStartRows((pageIndex-1)*pageSize);
}
public Integer getPageIndex() {
return pageIndex;
}
public void setPageIndex(Integer pageIndex) {
this.pageIndex = pageIndex;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getTotalCounts() {
return totalCounts;
}
//通过数据总行数对页大小取模是否为0, 从而判断总页数为多少
public void setTotalCounts(Integer totalCounts) {
this.totalCounts = totalCounts;
this.setTotalPages(totalCounts % pageSize == 0?totalCounts/pageSize:totalCounts/pageSize + 1 );
}
public Integer getTotalPages() {
return totalPages;
}
public void setTotalPages(Integer totalPages) {
this.totalPages = totalPages;
}
public Integer getStartRows() {
return startRows;
}
public void setStartRows(Integer startRows) {
this.startRows = startRows;
}
}
8.3.4 创建EmpDao接口
package com.dz.emp.dao;
import com.dz.emp.entity.Emp;
import com.dz.emp.entity.Page;
import java.util.List;
public interface EmpDao {
int insert(Emp emp);
int delete(int id);
int update(Emp emp);
Emp select(int id);
List<Emp> selectAll();
//分页查询所有
List<Emp> selectAll(Page page);
//查询数据总行数
long selectCounts();
}
8.3.5 EmpDaoImpl实现类
public class EmpDaoImpl implements EmpDao {
private QueryRunner queryRunner = new QueryRunner();
//此处省略其他方法
//分页查询所有
@Override
public List<Emp> selectAll(Page page) {
try {
List<Emp> empList = queryRunner.query(DbUtils.getConnection(), "select * from emp limit ?,?", new BeanListHandler<Emp>(Emp.class), page.getStartRows(),page.getPageSize());//两个参数分别为起始行和页大小
return empList;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
//查询数据总行数
@Override
public long selectCounts() {
try {
long counts = queryRunner.query(DbUtils.getConnection(), "select count(*) from emp", new ScalarHandler<>());
return counts;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return 0;
}
}
8.3.6 创建EmpService接口
package com.dz.emp.service;
import com.dz.emp.entity.Emp;
import com.dz.emp.entity.Page;
import java.util.List;
public interface EmpService {
int addEmp(Emp emp);
int removeEmp(int id);
int modify(Emp emp);
Emp showEmp(int id);
List<Emp> showAllEmp();
List<Emp> showAllEmp(Page page);
}
8.3.7 EmpServiceImpl实现类
public class EmpServiceImpl implements EmpService {
private EmpDao empDao = new EmpDaoImpl();
//此处省略其他方法
@Override
public List<Emp> showAllEmp(Page page) {
List<Emp> empList = new ArrayList<>();
try {
DbUtils.begin();
long counts = empDao.selectCounts();//查询共有多少条数据
page.setTotalCounts((int)counts);//将long类型的counts转换为int,并赋值给totalCounts
List<Emp> temp = empDao.selectAll(page);
if (temp != null) {
empList = temp;
}
DbUtils.commit();
} catch (Exception e) {
DbUtils.rollback();
e.printStackTrace();
}
return empList;
}
}
8.3.8 showAllEmpController实现
package com.dz.emp.controller;
import com.dz.emp.entity.Emp;
import com.dz.emp.entity.Page;
import com.dz.emp.service.EmpService;
import com.dz.emp.service.impl.EmpServiceImpl;
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.util.List;
@WebServlet(name = "ShowAllEmpController",value = "/manager/safe/showAllEmpController")
public class ShowAllEmpController extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pageIndex = request.getParameter("pageIndex");//获取到页码的值
if (pageIndex == null) {//用户第一次访问页码为空时
pageIndex = "1";//为页码赋值为1
}
Page page = new Page(Integer.valueOf(pageIndex));//将字符串格式的页码转换为Integer类型
EmpService empService = new EmpServiceImpl();
List<Emp> empList = empService.showAllEmp(page);
if (empList != null) {
request.setAttribute("page",page);
request.setAttribute("empList",empList);//存到request作用域中,临时存储
request.getRequestDispatcher("/manager/safe/showAllEmp.jsp").forward(request,response);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
8.3.9 showAllEmp.jsp
<%@ page import="com.dz.emp.entity.Emp" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>查询所有员工页面</title>
</head>
<body>
<form action="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showInsertEmp.jsp'></c:url>">
<p><input type='submit' value='新增'></p>
</form>
<table border='1'>
<tr>
<td>编号</td>
<td>姓名</td>
<td>工资</td>
<td>年龄</td>
<td colspan='2'>操作</td>
</tr>
<c:forEach var="emp" items="${empList}">
<tr>
<td>${emp.id}</td>
<td>${emp.name}</td>
<td>${emp.salary}</td>
<td>${emp.age}</td>
<td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/removeEmpController?id=${emp.id}'></c:url>">删除</a></td>
<td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showEmpController?id=${emp.id}'></c:url>">修改</a></td>
</tr>
</c:forEach>
<tr>
<td colspan="6">
<a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showAllEmpController?pageIndex=1'/> ">首页</a>
<c:if test="${page.pageIndex > 1}">
<a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showAllEmpController?pageIndex=${page.pageIndex-1}'></c:url> ">上一页</a>
</c:if>
<c:if test="${page.pageIndex == 1}">
<a>上一页</a>
</c:if>
<c:if test="${page.pageIndex < page.totalPages}">
<a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showAllEmpController?pageIndex=${page.pageIndex+1}'></c:url> ">下一页</a>
</c:if>
<c:if test="${page.pageIndex == page.totalPages}">
<a>下一页</a>
</c:if>
<a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showAllEmpController?pageIndex=${page.totalPages}'/> ">尾页</a>
</td>
</tr>
</table>
</body>
</html>
折叠
8.3.10 运行效果图
3_JSP的更多相关文章
- 3_Jsp标签_简单标签_防盗链和转义标签的实现
一概念 1防盗链 在HTTP协议中,有一个表头字段叫referer,采用URL的格式来表示从哪儿链接到当前的网页或文件,通过referer,网站可以检测目标网页访问的来源网页.有了referer跟踪来 ...
- shiro实现登录安全认证(转)
shiro实现登录安全认证 shiro的优势,不需要再代码里面判断是否登录,是否有执行的权限,实现了从前端页面到后台代码的权限的控制非常的灵活方便 传统的登录认证方式是,从前端页面获取到用户输入的账号 ...
随机推荐
- 4 zookeeper集群和基本命令
4 zookeeper集群和基本命令 集群思路:先搞定一台服务器,再克隆出两台,形成集群! 1 安装zookeeper 我们的zookeeper是安装在/opt目录下 2 配置服务器编号 在/opt/ ...
- OpenCV视频防抖技术解析
视频防抖有很多种技术,各有优劣,主流的目前分为三种:EIS电子防抖EIS电子防抖是通过软件算法实现防抖的.其技术运作原理是通过加速度传感器和陀螺仪模块侦测手机抖动的幅度,从而来动态调节整ISO.快门以 ...
- nodejs学习总结01
主流渲染引擎介绍1.渲染引擎又叫 排版引擎 或 浏览器内核 .(双内核:执行html和css的)2,主流的渲染引擎有**Chrome浏览器**:Blink引壁(WebKit的一个分支)**Safari ...
- 【Java中的线程】java.lang.Thread 类分析
进程和线程 联想一下现实生活中的例子--烧开水,烧开水时是不是不需要在旁边守着,交给热水机完成,烧开水这段时间可以去干一点其他的事情,例如将衣服丢到洗衣机中洗衣服.这样开水烧完,衣服洗的也差不多了.这 ...
- MySQL 启停过程了解一二
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. GreatSQL是MySQL的国产分支版本,使用上与MySQL一致. 前言 你知道MySQL启停都做了些什么吗? 启动的时 ...
- 设计模式(一)----设计模式概述及UML图解析
1.设计模式概述 1.1 软件设计模式的产生背景 "设计模式"最初并不是出现在软件设计中,而是被用于建筑领域的设计中. 1977年美国著名建筑大师.加利福尼亚大学伯克利分校环境结构 ...
- MySQL8.0解决“MySQL 服务无法启动。 服务没有报告任何错误。”
TL;NRs 初始化服务时最好使用mysqld --initialized --console命令: MySQL8.0的配置变量与MySQL5.7不同,[mysqld]下面设置字符集的变量名为char ...
- HDU 1542/POJ 1151 Atlantis (scaning line + segment tree)
A template of discretization + scaning line + segment tree. It's easy to understand, but a little di ...
- Linux 13 配置服务自启动
参考源 https://www.bilibili.com/video/BV187411y7hF?spm_id_from=333.999.0.0 版本 本文章基于 CentOS 7.6 准备 我们通常的 ...
- Java SE 10 新增特性
Java SE 10 新增特性 作者:Grey 原文地址:Java SE 10 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...