JSP 、JSTL、MVC分层思想——以登录验证为例
文章目录
- JSP & JSTL
- JSP 重点知识
- 基础概念
- 基础语法
- 指令标签
- 四大域对象
- EL 表达式
- JSTL 重点知识
- 基础使用
- 条件标签
- 迭代标签(forEach)
- 格式化标签
- 分层思想总结
- 分层架构设计
- 视图层(View)
- 控制层(Controller)
- 服务层(Service)
- 数据访问层(DAO/Mapper)
- 实体层(Pojo/Entity)
- 过滤器(Filter)
- 核心流程(登录验证)
- 分层思想优势
JSP & JSTL
JSP 重点知识
基础概念
JSP(Java Server Page)是 Java Web 服务器端动态资源,可嵌套 Java 代码生成动态数据,同时便于数据排版。本质上 JSP 就是 Servlet,首次访问时会被 JSP 引擎翻译成 Servlet,存于 Tomcat 的 work 目录
基础语法
- 注释:支持三种方式,// 和 /* */(Java 风格,隐式注释)、(HTML 风格,显示注释)、<%-- --%>(JSP 专属注释)
- Scriptlet:包含三种形式,
<% %>用于定义局部变量和编写语句,<%! %>用于定义全局变量、方法和类,<%= %>用于输出变量或具体内容
指令标签
- 静态包含:使用 <%@ include file=“文件路径” %>,编译时整合两个文件源码,生成一个 Servlet,不可有同名变量,耦合性高但效率略高
- 动态包含:使用 <jsp:include page=“文件路径”>,运行时动态调用,可传参(通过
jsp:param),包含与被包含部分独立,中间不可加无关内容(传参使用)
四大域对象
| 域对象 | 作用范围 | 核心方法 | 适用场景 |
|---|---|---|---|
| pageContext | 当前页面 | setAttribute(String name, Object o)``getAttribute(String name)``removeAttribute(String name) | 仅当前页面数据共享,跳转后失效 |
| request | 一次请求 | 同上 | 服务器跳转(如 forward)时数据共享,客户端跳转失效 |
| session | 一次会话(当前浏览器) | 同上 | 跨页面、跨请求数据共享,新浏览器打开失效 |
| application | 整个服务器(应用全局) | 同上 | 所有用户、所有会话共享数据,服务器重启失效 |
EL 表达式
- 语法:${expression},默认从小到大遍历四大域对象,未找到返回空字符串,可通过 pageScope、requestScope 等指定域对象
${pageScope.uname} <!-- page作用域 -->
${requestScope.uname} <!-- request作用域 -->
${sessionScope.uname} <!-- session作用域 -->
${applicationScope.uname} <!-- application作用域 -->
- 核心用途:获取域对象中 List、Map、JavaBean 的数据,通过
empty判断对象是否为空,支持等值、算术、大小比较等运算,非空判断:! empty
JSTL 重点知识
基础使用
JSTL需导入 jstl.jar 和 standard.jar,通过 <%@taglib uri=“标签库 URI” prefix=“前缀” %> 引入
-
核心标签库 URI 为:
http://java.sun.com/jsp/jstl/core -
格式化标签库 URI 为:
http://java.sun.com/jsp/jstl/fmt
条件标签
- if 标签:语法 <c:if test=“布尔表达式” var=“变量名” scope=“作用域”>,无 else 功能,需通过两个相反条件的 if 标签模拟
- choose、when、otherwise 标签:类似 Java 的 switch-case-default,choose 为容器。
- choose标签和otherwise标签没有属性,而when标签必须设置test属性
- choose标签中必须有至少一个when标签,可以没otherwise标签
- otherwise标签必须放在最后一个when标签之后
- choose标签中只能有when标签和otherwise标签,when标签和otherwise标签可以嵌套其他标签
- otherwise标签在所有的when标签不执行的情况下才会执行
迭代标签(forEach)
-
语法:<c:forEach items=“待循环数据” begin=“起始索引” end=“结束索引” step=“步长” var=“变量名” varStatus=“状态变量名”>
-
功能:可遍历集合(Collection、Map)、数组等
-
属性:
属性 描述 是否必要 默认值 items 要被循环的数据 否 无 begin 开始的元素(0 = 第一个元素,1 = 第二个元素) 否 0 end 最后一个元素(0 = 第一个元素,1 = 第二个元素) 否 Last element step 每一次迭代的步长 否 1 var 代表当前条目的变量名称 否 无 varStatus 代表循环状态的变量名称 否 无 varStatus 提供 index(0 开始索引)、count(1 开始计数)、first(是否首次迭代)、last(是否末次迭代)等状态
格式化标签
- formatNumber:格式化数字、百分比、货币,通过 type 指定类型,var 可存储格式化结果
| 属性 | 描述 | 是否必要 | 默认值 |
|---|---|---|---|
| value | 要显示的数字 | 是 | 无 |
| type | NUMBER, CURRENCY, 或 PERCENT 类型 | 否 | Number |
| var | 存储格式化数字的变量 | 否 | Print to page |
| scope | var 属性的作用域 | 否 | page |
- formatDate:格式化日期,支持 DATE、TIME、BOTH 类型,可通过 dateStyle、timeStyle 或 pattern 自定义格式
| 属性 | 描述 | 是否必要 | 默认值 |
|---|---|---|---|
| value | 要显示的日期 | 是 | 无 |
| type | DATE, TIME, 或 BOTH | 否 | date |
| dateStyle | FULL, LONG, MEDIUM, SHORT, 或 DEFAULT | 否 | default |
| timeStyle | FULL, LONG, MEDIUM, SHORT, 或 DEFAULT | 否 | default |
| pattern | 自定义格式模式 | 否 | 无 |
| timeZone | 显示日期的时区 | 否 | 默认时区 |
| var | 存储格式化日期的变量名 | 否 | 显示在页面 |
| scope | 存储格式化日志变量的范围 | 否 | 页面 |
- parseNumber/parseDate:分别用于将字符串解析为数字(或百分比、货币)和 Date 类型,需指定对应 type 或 pattern
| 属性 | 描述 | 是否必要 | 默认值 |
|---|---|---|---|
| value | 要解析的数字 | 否 | Body |
| type | NUMBER, CURRENCY, 或 PERCENT | 否 | number |
| var | 存储待解析数字的变量 | 否 | Print to page |
| scope | var 属性的作用域 | 否 | page |
| 属性 | 描述 | 是否必要 | 默认值 |
|---|---|---|---|
| value | 要显示的日期 | 是 | 无 |
| type | DATE, TIME, 或 BOTH | 否 | date |
| dateStyle | FULL, LONG, MEDIUM, SHORT, 或 DEFAULT | 否 | default |
| timeStyle | FULL, LONG, MEDIUM, SHORT, 或 DEFAULT | 否 | default |
| pattern | 自定义格式模式 | 否 | 无 |
| var | 存储格式化日期的变量名 | 否 | 显示在页面 |
| scope | 存储格式化日志变量的范围 | 否 | 页面 |
分层思想总结
MVC 分层思想,实现 “视图层 - 控制层 - 服务层 - 数据访问层” 的解耦开发
分层架构设计
视图层(View)
- 核心职责:展示页面、收集用户输入、显示处理结果(前端)
- 实现文件:
login.jsp(登录表单,收集用户名 / 密码,显示登录失败提示)、index.jsp(登录成功后的项目首页) - 关键技术:HTML 表单提交(
action指向控制层 Servlet)、EL 表达式(${failmsg}显示失败信息)
控制层(Controller)
-
核心职责:接收请求、参数封装、调用服务层(service)、控制页面跳转(后端)
-
实现文件:
LoginServlet.java(注解@WebServlet("/loginServlet")映射请求路径) -
核心逻辑:
- 接收页面传递的
uname和pwd参数; - 对参数进行非空校验;
- 调用服务层方法查询用户信息;
- 进行用户校验,通过后进行密码校验(精确打印错误信息)
- 登录成功:将用户信息存入
session,重定向到index.jsp; - 登录失败:将失败信息存入
request,请求转发回login.jsp。
- 接收页面传递的
服务层(Service)
- 核心职责:封装业务逻辑判断,并将处理结果返回给控制层(Controller 层)
- 实现结构:接口(
UserService.java)+ 实现类(UserServiceImpl.java) - 核心逻辑:定义
selectUserInfo方法,通过调用数据访问层的selectOneUser方法获取用户数据,不直接操作数据库
数据访问层(DAO/Mapper)
-
核心职责:与数据库交互,执行 CRUD 操作,封装数据访问细节。
-
实现结构:接口(
UserDao.java)+ 实现类(UserDaoImpl.java)。 -
核心逻辑:
- 加载 MySQL 驱动,建立数据库连接;
- 编写预编译 SQL(
select * from t_user where uname = ? and pwd = ?); - 执行查询,将结果集封装为
User实体对象; - 关闭数据库资源(Connection、PreparedStatement、ResultSet)
实体层(Pojo/Entity)
- 核心职责:封装数据,与数据库中的表一一对应
- 实现文件:
User.java,包含uid、uname、pwd属性,提供无参 / 有参构造方法、getter/setter 方法和toString方法(Javabean)
过滤器(Filter)
- 核心职责:拦截非法访问(未登录直接访问首页),控制资源放行
- 实现文件:
LoginFilter.java(注解@WebFilter("/*")拦截所有请求) - 放行规则:登录页面(
login.jsp)、静态资源(/images)、登录操作(/loginServlet)、已登录状态(session中存在user对象)
核心流程(登录验证)
- 用户在
login.jsp输入用户名和密码,提交表单到LoginServlet; - 控制层接收参数,调用服务层
selectUserInfo方法; - 服务层调用数据访问层
selectOneUser方法,执行数据库查询; - 数据访问层返回
User对象(查询成功)或null(查询失败); - 控制层根据结果跳转:成功则存入
session并重定向到index.jsp,失败则存入提示信息并转发回login.jsp; - 过滤器拦截所有请求,未登录用户直接访问首页时,重定向到
login.jsp。
分层思想优势
- 耦合性低:各层职责独立,修改视图层不影响业务逻辑,修改数据库操作不影响控制层;
- 重用性高:服务层和数据访问层的方法可被多个控制层复用;
- 职责明确:开发人员可分工负责(前端开发视图层、后端开发服务层 / 数据层);
- 可维护性高:分层结构清晰,问题定位和代码修改更高效
