一. 引言
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
- 修改:
- 访问:
- 标签:
- printWriter.println("< html>");
JSP
- 编码
- 修改:
- 访问:
- 标签:
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 脚本
4.1.1 普通脚本
| <%@ page contentType="text/html;charset=UTF-8" language="java" %> |
| <html> |
| <head> |
| <title>脚本的使用</title> |
| </head> |
| <body> |
| <% |
| |
| 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 输出脚本
| <%@ 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(); |
| pageContext.getResponse(); |
| pageContext.getSession(); |
| pageContext.getServletContext(); |
| pageContext.getOut(); |
| pageContext.getException(); |
| pageContext.getPage(); |
| pageContext.getServletConfig(); |
| %> |
4.5.4 pageContext操作其他内置对象的作用域
- pageContext对象可以操作其他作用域存储和获取
| <% |
| |
| pageContext.setAttribute("page", "123", PageContext.PAGE_SCOPE); |
| pageContext.setAttribute("req","aaa", PageContext.REQUEST_SCOPE); |
| pageContext.setAttribute("session","bbb", PageContext.SESSION_SCOPE); |
| pageContext.setAttribute("application","ccc", PageContext.APPLICATION_SCOPE); |
| |
| |
| String value = (String) pageContext.getAttribute("page"); |
| String value1 = (String) request.getAttribute("req"); |
| String value2 = (String) session.getAttribute("session"); |
| String value3 = (String) application.getAttribute("application"); |
| String value4 = (String) pageContext.findAttribute("req"); |
| %> |
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"); |
| 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的运算符
操作符
-
.
-
[]
-
-
-
-
/ 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 隐式对象
- pageScope
- requestScope
- sessionScope
- applicationScope
- param
- paramValues
- header
- headerValues
- initParam
- cookie
- 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使用
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):
- 对客观世界的一种代表和模拟(业务模拟, 对象模拟)
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 |
| |
| 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; |
| |
| |
| public Page(Integer pageIndex) { |
| this(pageIndex,5); |
| } |
| |
| |
| 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; |
| } |
| |
| |
| 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); |
| 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"; |
| } |
| Page page = new Page(Integer.valueOf(pageIndex)); |
| |
| EmpService empService = new EmpServiceImpl(); |
| List<Emp> empList = empService.showAllEmp(page); |
| if (empList != null) { |
| request.setAttribute("page",page); |
| request.setAttribute("empList",empList); |
| 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 运行效果图

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步