7_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

  1. 编码:
    • 继承HttpServlet + 注解或配置web.xml
  2. 修改:
    • 重新部署, 重启服务器
  3. 访问:
  4. 标签:
    1. printWriter.println("< html>");

JSP

  1. 编码
    • HTML中直接编写Java代码
  2. 修改:
    • 刷新页面
  3. 访问:
  4. 标签:
    • 直接编写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个隐式对象
  1. pageScope
    • page作用域
  2. requestScope
    • request作用域
  3. sessionScope
    • session作用域
  4. applicationScope
    • application作用域
  5. param
    • Request对象的参数, 字符串
  6. paramValues
    • Request对象的参数, 字符串
  7. header
    • HTTP信息头, 字符串
  8. headerValues
    • HTTP信息头, 字符串集合
  9. initParam
    • 上下文初始化参数
  10. cookie
    • Cookie值
  11. 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}&nbsp;&nbsp;${vs.first}&nbsp;&nbsp;${vs.last}&nbsp;&nbsp;${vs.count}&nbsp;&nbsp;${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):
      • 对客观世界的一种代表和模拟(业务模拟, 对象模拟)

7.3 优点

  • 低耦合性: 模块与模块之间的关联性不强, 不与某一种具体实现产生密不可分的关联性
  • 高维护性: 基于低耦合性, 可做到不同层级的功能模块灵活更换, 插拔
  • 高重用性: 相同的数据库操作, 可以服务于不同的业务处理, 将数据作为独立模块, 提高重用性

7.4 MVC在框架中应用

  • MVC模式被广泛用于Java的各种框架中, 比如Struct2, SpringMVC等都用到了这种思想

7.5 三层架构与MVC

7.5.1 三层架构
  • View层 (表示|界面层)、Service层 (业务逻辑层)、DAO层(数据访问层)

  • 表示层(UI, Main)

    • 职责:
      1. 收集用户输入数据
      2. 调用业务逻辑层, 完成业务方法
      3. 展示数据或展示操作结果
  • 业务逻辑层(service)

    • 职责:
      1. 开启事务
      2. 调用DAO层
      3. 处理数据
      4. 提交或回滚
  • 数据访问层(DAO)

    • 职责:
      1. 查询相关业务逻辑的数据
      2. 根据相关业务逻辑修改的数据
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 分页代码实现

  • 步骤
    1. 确定每页显示的数据数量
    2. 确定分页显示所需的总页数
    3. 编写SQL查询语句, 实现数据查询
    4. 在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 运行效果图

7_JSP

7_JSP

上一篇:HTML+CSS面试题


下一篇:kubernetes入门