JSP
java Server Pages:Java服务器端页面,也和Servlet应用,用于动态web
1.特点:
-
写JSP就像再写HTML
-
区别
-
HTML只给用户提供静态的数据
-
JSP页面中可以嵌入Java代码,为用户提供动态数据
-
2.原理
浏览器像服务器发送请求,不管访问什么资源,其实都是在访问Servlet
JSP最终也会被转换成为一个Java类
JSP本质上就是一个Servlet
在JSP页面中,只要是java代码就会原封不动的输出
HTML代码,就会被转换成:out.write("<html>\r\n");
3.JSP基础语法
<%--JSP表达式 作用将程序的输出,输出到客户端 <%= 变量或者表达式%> --%> <%= new java.util.Date()%>
<%--JSP脚本片段--%> <% int sum = 0; for (int i = 1; i <100 ; i++) { sum+=i; } out.println(sum); %>
JSP声明:会被编译到ISP生成Java的类中!其他的,就会被生成到_jspService方法中!
JSP的注释,不会在客户端显示,HTML就会!
4.JSP指令
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%--@include会将两个页面合二为一--%> <%@include file="common/header.jsp"%> <h1>网页主体</h1> <%@include file="common/footer.jsp"%> <hr> <%--jsp标签 jsp:include: 拼接页面,本质还是三个 --%> <jsp:include page="/common/header.jsp"/> <h1>网页主体</h1> <jsp:include page="/common/footer.jsp"/> </body> </html>
5.九大内置对象
-
PageContext 存东西
-
Request 存东西
-
Response
-
Session 存东西
-
Application 【ServletContext】存东西
-
config 【ServletConfig】
-
out
-
page
-
exception
从pageContext取出,我们通过寻找的方式来 从底层到高层(作用域):page->request-->session-->application
<%-- 内置对象--%> <% pageContext.setAttribute("name1", "秦疆1号"); // 保存的数据只在一个页面中有效 request.setAttribute("name2", "秦疆2号"); // 保存的数据只在一次请求中有效,请求转发会携带这个数据 session.setAttribute("name3", "秦疆3号"); // 保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器 application.setAttribute("name4", "秦疆4号"); // 保存的数据只在服务器中有效,从打开服务器到关闭服务器 %> <%-- 脚本片段中的代码,会被原封不动生成到.JSP.java 要求:这里面的代码:必须保证Java语法的正确性 --%> <% // 从pageContext取出,我们通过寻找的方式来 // 从底层到高层(作用域):page->request-->session-->application String name1 = (String) pageContext.findAttribute("name1"); String name2 = (String) pageContext.findAttribute("name2"); String name3 = (String) pageContext.findAttribute("name3"); String name4 = (String) pageContext.findAttribute("name4"); String name5 = (String) pageContext.findAttribute("name5"); // 不存在 %> <%-- 使用EL表达式输出 ${} --%> <h1>取出的值为:</h1> <h3>${name1}</h3> <h3>${name2}</h3> <h3>${name3}</h3> <h3>${name4}</h3> <h3><%=name5%> </h3>
request:客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻,用户看完没用的!
session:客户端向服务器发送请求,产生的数据,用户用完一会还有用,比如:购物车;
application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:聊天数据;
8.6JSP标签,JSTL标签,EL表达式
需要导包
<!--JSTL表达式的依赖--> <!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl-api --> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl-api</artifactId> <version>1.2</version> </dependency> <!--standard标签库--> <!-- https://mvnrepository.com/artifact/taglibs/standard --> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency>
EL表达式:${}
-
获取数据
-
执行运算
-
获取web开发的常用对象
-
调用Java方法
JSP标签
<%--jsp:include--%> <%-- http://localhost:8080/jsptag.jsp?name=kuangshen&age=12 --%> <jsp:forward page="/jsptag2.jsp"> <jsp:param name="name" value="kuangshen"></jsp:param> <jsp:param name="age" value="12"></jsp:param> </jsp:forward>
JSTL标签
JSTL标签库的使用就是为了弥补HTML的标签的不足;
它自定义许多标签,可以供我们使用,标签的的功能和Java代码一样
需要导入JSTL标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%--引入JSTL核心标签库,我们才能使用JSTL标签 core--%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Title</title> </head> <body> </body> </html>
核心标签
9.JavaBean
实体类
JavaBean有特定的写法:
-
必须有一个无参构造
-
属性必须私有化
-
必须有对应的get/set方法
一般用来和数据库的字段做映射 ORM
ORM:对象关系映射
-
表--->类
-
字段--->属性
-
行记录--->对象
10.MVC三层架构
Model 模型
View 视图
Controller 控制器
用户直接访问控制层,控制层就可以直接操作数据库
servlet--CRUD--数据库 弊端:程序十分臃肿,不利于维护 servlet的代码中:处理请求,响应,视图跳转,处理JDBC,处理业务代码,处理逻辑代码 架构 程序员调用 | JDBC | MySQL Oracle sqlServer
Model
-
业务处理:业务逻辑(Service)
-
数据持久层:CRUD (Dao)
View
-
展示数据
-
提供连接发起Service请求(a,form,img)
Controller(Service)
-
接受用户的请求:(req:请求参数,Session信息)
-
交给业务层处理对应的代码
-
控制视图的跳转
登录-->接收用户的登录请求-->处理用户的请求(获取用户登录的参数,username,password)-->交给业务层处理登录业务(判断用户名密码是否正确:事务)-->Dao层查询用户名和密码是否正确
11.Filter
过滤器,用来过滤网站的数据
Filter开发步骤:
1.导包
2.编写过滤器
导包别错了,import jakarta.servlet.*;
实现Filter接口,重写对应的方法
package com.lyj.servlet; import jakarta.servlet.*; import java.io.IOException; public class CharacterEncodingFilter implements Filter { //初始化,web服务器启动,就已经初始化了,随时等待过滤对象出现 @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("CharacterEncodingFilter init初始化chushihua=========="); } //chain 链 // // 1.过滤中的所有代码,在过滤特定请求的时候都会执行 // 2.必须要让过滤器继续同行 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("UTF-8"); servletResponse.setCharacterEncoding("UTF-8"); servletResponse.setContentType("text/html;charset=UTF-8"); System.out.println("CharacterEncodingFilter执行之前"); //让我们的请求继续走,如果不写,程序到这里就会被拦截停止 filterChain.doFilter(servletRequest, servletResponse); System.out.println("CharacterEncodingFilter执行之后"); } @Override public void destroy() { System.out.println("CharacterEncodingFilter destroy销毁xiaohui================"); } }
3.在web.xml中配置Filter
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" version="6.0"> <display-name>Welcome to Tomcat</display-name> <description>Welcome to Tomcat</description> <servlet> <servlet-name>ShowServlet</servlet-name> <servlet-class>com.lyj.servlet.ShowServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ShowServlet</servlet-name> <url-pattern>/show</url-pattern> </servlet-mapping> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.lyj.servlet.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/servlet</url-pattern> </filter-mapping> </web-app>
12.监听器
package listener; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpSessionEvent; import jakarta.servlet.http.HttpSessionListener; import java.util.concurrent.atomic.AtomicInteger; // 统计网站在线人数:通过监听Session创建与销毁实现 public class OnlineCountListener implements HttpSessionListener { // 使用线程安全的AtomicInteger替代普通Integer,解决并发问题 private AtomicInteger onlineCount; @Override public void sessionCreated(HttpSessionEvent se) { ServletContext ctx = se.getSession().getServletContext(); // 从ServletContext中获取计数器,若不存在则初始化 onlineCount = (AtomicInteger) ctx.getAttribute("OnlineCount"); if (onlineCount == null) { onlineCount = new AtomicInteger(1); } else { // 线程安全的自增操作 onlineCount.incrementAndGet(); } ctx.setAttribute("OnlineCount", onlineCount); } @Override public void sessionDestroyed(HttpSessionEvent se) { ServletContext ctx = se.getSession().getServletContext(); onlineCount = (AtomicInteger) ctx.getAttribute("OnlineCount"); if (onlineCount == null) { onlineCount = new AtomicInteger(0); } else { // 线程安全的自减操作,确保不会出现负数 onlineCount.decrementAndGet(); if (onlineCount.get() < 0) { onlineCount.set(0); } } ctx.setAttribute("OnlineCount", onlineCount); } }
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" version="6.0"> <display-name>Welcome to Tomcat</display-name> <description>Welcome to Tomcat</description> <servlet> <servlet-name>ShowServlet</servlet-name> <servlet-class>com.lyj.servlet.ShowServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ShowServlet</servlet-name> <url-pattern>/show</url-pattern> </servlet-mapping> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.lyj.servlet.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/servlet</url-pattern> </filter-mapping> <listener> <listener-class>listener.OnlineCountListener</listener-class> </listener> </web-app>
<%@ page import="java.util.concurrent.atomic.AtomicInteger" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <h2>Hello World!</h2> <% // 从ServletContext中获取在线人数计数器 AtomicInteger onlineCount = (AtomicInteger) application.getAttribute("OnlineCount"); // 处理空值情况,默认为0 int count = (onlineCount != null) ? onlineCount.get() : 0; %> <h1>当前有<span><%= count %></span>人在线</h1> </body> </html>
13.过滤器,监听器应用
用户登录之后才能进入主页,用户注销后就不能进入主页了
1.用户登录之后,向Session中放入用户的数据
2.进入主页的时候要判断用户是否已经登录,要求:在过滤器中实现
LoginServlet
package com.lyj.servlet; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; public class LoginServlet extends HttpServlet { // 定义常量,便于维护 private static final String VALID_USERNAME = "admin"; private static final String SUCCESS_PAGE = "/sys/success.jsp"; private static final String ERROR_PAGE = "/error.jsp"; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 设置编码,确保中文正常处理 req.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8"); // 获取前端请求的参数 String username = req.getParameter("username"); // 登录成功/失败判断,使用常量避免硬编码,先判断非空 if (username != null && VALID_USERNAME.equals(username)) { // 存储用户会话标识 req.getSession().setAttribute("USER_SESSION", req.getSession().getId()); resp.sendRedirect(req.getContextPath() + SUCCESS_PAGE); } else { resp.sendRedirect(req.getContextPath() + ERROR_PAGE); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 支持POST请求,直接调用doGet方法 doGet(req, resp); } }
LogoutServlet
package com.lyj.servlet; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; public class LogoutServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取用户会话属性(注意:原代码中属性名可能拼写错误,此处统一用正确名称) Object userSession = req.getSession().getAttribute("USER_SESSION"); // 逻辑修正:如果存在用户会话,则销毁会话 if (userSession != null) { // 使整个会话失效(比单独移除属性更彻底) req.getSession().removeAttribute("USER_SESSION"); //req.getSession().invalidate(); // 跳转到登录页(使用上下文路径,避免硬编码问题) resp.sendRedirect(req.getContextPath() + "/login.jsp"); } else { // 若会话不存在,直接跳转到错误页或登录页 resp.sendRedirect(req.getContextPath() + "/error.jsp"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 支持POST请求,复用doGet逻辑 doGet(req, resp); } }
SysFilter
package com.lyj.listener; import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; /** * 系统过滤器:拦截/sys/*路径的请求,验证用户是否已登录 * 未登录用户将被重定向到错误页,已登录用户允许继续访问 */ public class SysFilter implements Filter { /** * 过滤器初始化方法 * 可用于加载过滤器所需的配置参数等初始化操作 */ @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化逻辑(如无特殊需求可留空) Filter.super.init(filterConfig); } /** * 核心过滤方法:验证用户登录状态 * @param servletRequest 请求对象 * @param servletResponse 响应对象 * @param filterChain 过滤器链,用于传递请求到下一个组件 */ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 类型转换:将ServletRequest转为HttpServletRequest以使用HTTP相关方法 HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // 从会话中获取用户登录标识(与登录逻辑中的属性名保持一致) Object userSession = request.getSession().getAttribute("USER_SESSION"); // 验证逻辑:如果用户未登录(会话中无USER_NAME) if (userSession == null) { // 重定向到错误页(使用上下文路径避免路径问题) response.sendRedirect(request.getContextPath() + "/error.jsp"); // 注意:重定向后需return,避免继续执行后续逻辑 return; } // 若用户已登录,将请求传递给下一个过滤器或目标资源 filterChain.doFilter(request, response); } /** * 过滤器销毁方法 * 可用于释放过滤器占用的资源 */ @Override public void destroy() { // 销毁逻辑(如无特殊需求可留空) } }
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" version="6.0"> <display-name>Welcome to Tomcat</display-name> <description>Welcome to Tomcat</description> <servlet> <servlet-name>ShowServlet</servlet-name> <servlet-class>com.lyj.servlet.ShowServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ShowServlet</servlet-name> <url-pattern>/show</url-pattern> </servlet-mapping> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.lyj.servlet.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/servlet</url-pattern> </filter-mapping> <listener> <listener-class>com.lyj.listener.OnlineCountListener</listener-class> </listener> <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>com.lyj.servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> <servlet> <servlet-name>LogoutServlet</servlet-name> <servlet-class>com.lyj.servlet.LogoutServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LogoutServlet</servlet-name> <url-pattern>/logout</url-pattern> </servlet-mapping> <filter> <filter-name>SysFilter</filter-name> <filter-class>com.lyj.listener.SysFilter</filter-class> </filter> <filter-mapping> <filter-name>SysFilter</filter-name> <url-pattern>/sys/*</url-pattern> </filter-mapping> </web-app>
success,.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>success</title> </head> <body> <h1>主页</h1> <h3></h3> <!-- 动态拼接应用上下文路径,避免路径错误 --> <p><a href="${pageContext.request.contextPath}/logout">注销</a></p> </body> </html>
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>login</title> </head> <body> <h1>登录!!!!!!!!!</h1> <form action="${pageContext.request.contextPath}/login"method="post"> <input type="text" name="username" > <input type =submit> </form> </body> </html>
error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>错误错误</h1> <h3>没有权限,用户名错误</h3> <a href="login.jsp">返回登录页面</a> </body> </html>