目录

  • 1. session和cookie
    • 1.1 session和cookie原理
    • 1.2 cookie—实现10天免登录
    • 1.3 session—实现记住用户名
  • 2. servletContext
    • 2.1 统计网站访问次数
    • 2.2 ServletAPI 总结
    • 3.2 创建实体类
    • 3.3 DBUtil类
    • 3.4 创建 Dao层
    • 3.5 在 servlet中使用
    • 3.6 在 JSP中处理
  • 4. MVC模式
    • 4.1 提取业务层
    • 4.2 JavaBean
    • 4.3 用户注册案例
    • 4.4 合并Servlet
  • 5. JSP高级内容
    • 5.1 JSP执行原理
    • 5.2 九大内建对象
    • 5.3 四个作用域
  • 6. JSTL/EL表达式
    • 6.1 EL表达式
    • 6.2 JSTL表达式
    • 6.3 有条件的查询用户信息
  • 7. 过滤器
    • 7.1 解决中文乱码
    • 7.2 权限验证
    • 7.3 更多原理
  • 8. 监听器
    • 8.1 作用及分类
    • 8.2 监听用户请求
    • 8.3 使用场合举例

1. session和cookie

1.1 session和cookie原理

HTTP协议是无状态的协议,客户每次读取 web 页面,服务器都会打开新的连接,而且服务器也不会自动维护客户的上下文信息。

如何在多次请求之间共享信息呢? 服务器端如何判断一个分时段的连接是不是属于同一个客户呢?

Session 和 Cookie 就是为解决 HTTP协议的无状态采用的两种解决方案

  • Cookie:将信息保存在客户端解决
  • Session:将信息保存在服务器端解决

1.2 cookie—实现10天免登录

重定向:可以拿到 cookie(返回到页面再跳转,所以可以拿到)

转发:拿不到 cookie(服务器内部转发,页面拿不到)

LoginServlet.java

  • 创建一个 cookie
  • 指定 cookie 作用范围(默认范围是当前目录)
  • 指定 cookie 有效时间(默认有效时间是当前浏览器打开时)
  • 把 cookie 给客户端
public class LoginServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8");String username = req.getParameter("username");String pwd = req.getParameter("pwd");String remember = req.getParameter("remember");   // 根据勾选判断是否记住// 增加一个服务器端格式验证,验证数据合法性// TODO// 应该调用后台(JDBC)判断登录是否成功;此处直接处理boolean flag = false;if (username.contains("lwclick") && pwd.contains("click")) {flag = true;}if (flag) {// ==================================== 完成 10天免登录功能 ====================================// 创建一个 cookieCookie usernameCookie = new Cookie("uname", username);Cookie pwdCookie = new Cookie("upwd", pwd);// 指定 cookie 作用范围(默认范围是当前目录)usernameCookie.setPath(req.getContextPath());    // 作用范围当前项目pwdCookie.setPath(req.getContextPath());if ("yes".equals(remember)) {// 指定 cookie 有效时间(默认有效时间是当前浏览器打开时)usernameCookie.setMaxAge(60 * 60 * 24 * 10);pwdCookie.setMaxAge(60 * 60 * 24 * 10);} else {// 去掉 cookieusernameCookie.setMaxAge(0);pwdCookie.setMaxAge(0);}// 把 cookie 给客户端resp.addCookie(usernameCookie);resp.addCookie(pwdCookie);// ==================================== 10天免登录功能 end ====================================// 跳转到成功页面 【重定向 redirect】req.setAttribute("username", username);resp.sendRedirect(req.getContextPath() + "/login/success.jsp");} else {// 跳回登录页 【转发 dispatcher】req.setAttribute("error", "用户名或密码错误");req.getRequestDispatcher("/login/login.jsp").forward(req, resp);}}
}

login.jsp页面

  • 拿出所有的 cookie
  • 找到需要的 cookie
  • 使用 cookie
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录页面</title><script type="text/javascript" src="../js/jquery-1.9.1.js"></script><script type="text/javascript"><!--    客户端验证 省略    --></script>
</head>
<body><%// 1. 拿出所有的 cookieCookie[] cookies = request.getCookies();// 2. 找到需要的 cookieString username = "";String password = "";String isChecked = "";if (cookies != null) {for (int i = 0; i < cookies.length; i++) {if ("uname".equals(cookies[i].getName())) {username = cookies[i].getValue();isChecked = "checked";}if ("upwd".equals(cookies[i].getName())) {password = cookies[i].getValue();}}// 使用 cookie// 在用户名和密码的输入框中,使用 value 字段绑定值}
%><form action="../servlet/LoginServlet" method="post" onsubmit="return checkForm()">用户名:<input type="text" id="username" name="username" value="<%=username%>" onblur="checkUser()"/><!-- 错误提示,省略 --><br>密码: <input type="text" id="password" name="pwd" value="<%=password%>" onblur="checkPwd()"/><!-- 错误提示,省略 --><br><input name="remember" type="checkbox" value="yes" <%=isChecked%>/>十天免登录<br> <!-- 复选框,勾中才记住 --><input type="submit" value="登录">
</form>
</body>
</html>

1.3 session—实现记住用户名

  • 首次访问服务器上的一个JSP页面时,JSP引擎产生一个session对象
  • 每个session都有一个sessionid
  • 数据保存在服务器端, 将sessionid保存在客户端的Cookie中(服务器端也有sessionId,用来对照)
  • 后续每次请求request都携带cookie到服务器端
  • 服务器端根据客户端的sessionid判断属于哪个会话

LoginServlet.java

public class LoginServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8");// 接收用户编号和密码String username = req.getParameter("username");String pwd = req.getParameter("pwd");String remember = req.getParameter("remember");  // 根据勾选判断是否记住// 增加一个服务器端格式验证,验证数据合法性// TODO// 应该调用后台(JDBC)判断登录是否成功;此处直接处理boolean flag = false;if (username.contains("lwclick") && pwd.contains("click")) {flag = true;}if (flag) {// ==================================== 记住用户名 ====================================HttpSession session = req.getSession();session.setAttribute("username", username);// ==================================== 记住用户名 end ====================================// 跳转到成功页面 【重定向 redirect】resp.sendRedirect(req.getContextPath() + "/login/success.jsp");} else {// 跳回登录页 【转发 dispatcher】req.setAttribute("error", "用户名或密码错误");req.getRequestDispatcher("/login/login.jsp").forward(req, resp);}}
}

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title><%String basePath = request.getScheme() + "://" + request.getServerName() +":" + request.getServerPort() + request.getContextPath() + "/";%><base href="<%=basePath%>">
</head>
<body><!--  session 代表当前会话,一个用户一定时间内的多个请求 -->登录成功!欢迎<%=session.getAttribute("username")%>  <!-- 使用session可以在【当前项目】的【所有页面】中访问到 --><!--  可以用 sessionId 判断是否为同一个session  --><%=session.getId()%><!--  设置 session过期时间,过期后结束  --><% session.setMaxInactiveInterval(10) %><!--  注销操作  --><a href="servlet/LogoutServlet">注销</a>
</body>
</html>

LogoutServlet.java

public class LogoutServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 立即结束当前的 sessionreq.getSession().invalidate();// 跳回登录页面(注销操作建议使用重定向)resp.sendRedirect(req.getContextPath() + "/login/login.jsp");}
}

注意:有的浏览器不支持 cookie时,可以通过 URL重写(http://localhost:8080/sevlet/LoginServelt?sessionId=354nlehtbbew54,每次都传sessionId)的方式,来实现 session对象的唯一性

2. servletContext

2.1 统计网站访问次数

ServletContext

  • 代表 web应用本身,相当于 web应用的全局变量,整个 web应用共享一个 servletContext对象

  • 关闭服务器,servletContext数据清空

    session的数据还在(tomcat会在服务器关闭时,自动保存session信息到硬盘)

LoginServlet.java

public class LoginServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8");// 接收用户编号和密码String username = req.getParameter("username");String pwd = req.getParameter("pwd");String remember = req.getParameter("remember");  // 根据勾选判断是否记住// 增加一个服务器端格式验证,验证数据合法性// TODO// 应该调用后台(JDBC)判断登录是否成功;此处直接处理boolean flag = false;if (username.contains("lwclick") && pwd.contains("click")) {flag = true;}if (flag) {// ==================================== 统计网站的访问人数 ====================================// 获取之前的人数ServletContext servletContext = req.getServletContext();   // this.getServletContext();Integer count = (Integer) servletContext.getAttribute("count");if (count == null) {count = 1;} else {count++;}servletContext.setAttribute("count", count);// ==================================== 统计网站的访问人数 end ====================================// 跳转到成功页面 【重定向 redirect】resp.sendRedirect(req.getContextPath() + "/login/success.jsp");} else {// 跳回登录页 【转发 dispatcher】req.setAttribute("error", "用户名或密码错误");req.getRequestDispatcher("/login/login.jsp").forward(req, resp);}}
}

2.2 ServletAPI 总结

  • Servlet

    • Servlet、 GenericServlet、 HttpServlet
  • 请求和响应

    • ServletRequest、 ServletResponse
    • HttpServletRequest、 HttpServletResponse
  • 会话和上下文

    • HttpSession、 Cookie、 ServletContext
  • 配置

    • ServletConfig
  • 请求转发

    • RequestDispatcher
  • 异常

    • ServletException
  • Cookie类

    • Cookie cookie = new Cookie(name,value);
  • HttpSession接口

    • HttpSession session=request.getSession();
  • ServletContext接口

    • 上下文表示每个Web应用程序的环境,且被当作是一个应用程序中所有servlet可访问的共享库
    • ServletContext context=this.getServletContext();
  • ServletConfig接口

    • ServletConfig是表示单独的Servlet的配置和参数,只是适用于特定的Servlet。
    • 从servlet访问一个servlet被实例化后,对任何客户端在任何时候访问有效,但仅对本servlet有效,一个servlet的ServletConfig对象不能被另一个
    • ServletConfig config = this.getServletConfig();

# 3. 访问数据库完善登录功能 ## 3.1 创建数据表

CREATE TABLE sys_user (userid VARCHAR(10) PRIMARY KEY,realname VARCHAR(20) NOT NULL,pwd VARCHAR(10),age INT(3)
);INSERT INTO sys_user VALUES ("zhangsan", "张三", "zhangsan123", 23);

3.2 创建实体类

public class SysUser {private String userId;private String realName;private String pwd;private Integer age;public SysUser(String userId, String realName, String pwd, Integer age) {this.userId = userId;this.realName = realName;this.pwd = pwd;this.age = age;}public SysUser() {}// getter、 setter、 toString
}

3.3 DBUtil类

简单封装的

public class DBUtil {private DBUtil(){}/*** 获取数据库连接* @return*/public static Connection getConnection(){String driver ="com.mysql.cj.jdbc.Driver";String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";String user = "root";String password = "root";Connection conn = null;try {//1.加载驱动Class.forName(driver);//2.建立和数据库的连接conn = DriverManager.getConnection(url, user, password);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();}return conn;}/*** 关闭各种资源* @param rs* @param stmt* @param conn*/public static void closeAll(ResultSet rs, Statement stmt, Connection conn){try {if(rs!=null){rs.close();}} catch (SQLException e) {e.printStackTrace();}try {if(stmt != null){stmt.close();}} catch (SQLException e) {e.printStackTrace();}try {if(conn != null){conn.close();}} catch (SQLException e) {e.printStackTrace();}}/*** 完成DML操作:insert、update和delete* @param sql* @param params* @return*/public static int executeUpdate(String sql, Object [] params) {Connection conn = null;PreparedStatement pstmt = null;ResultSet rs =  null;int n = 0;//添加失败try {//2.建立和数据库的连接conn = DBUtil.getConnection();//3.创建一个SQL命令发送器pstmt = conn.prepareStatement(sql);//4.准备好SQL语句,通过SQL命令发送器发送给数据库,并得到结果for (int i = 0; i <params.length ; i++) {pstmt.setObject(i+1, params[i]);}n = pstmt.executeUpdate();} catch (SQLException e) {e.printStackTrace();} finally {//6.关闭资源DBUtil.closeAll(rs, pstmt, conn);}return n;}
}

3.4 创建 Dao层

DAO=Data Access Object 数据访问(存取)对象

DAO层=数据访问层

DAO模式包括以下元素:

  • UserDao --> DAO接口
  • UserDaoImpl --> DAO实现类
  • BaseDao或者DBUtil --> 数据库操作工具类
  • User实体类
/*** Dao 面对的是数据库,只有增删改查操作*/
public interface UserDao {/*** 查询用户* @param userId* @param password* @return*/SysUser find(String userId, String password);/*** 保存用户* @param user* @return*/int save(SysUser user);
}

实现类

public class UserDaoImpl implements UserDao {@Overridepublic SysUser find(String userId, String password) {Connection conn = null;PreparedStatement pstmt = null;ResultSet rs =  null;SysUser user = null;try {conn = DBUtil.getConnection();String sql = "select * from user where userid = ? and pwd = ?";pstmt = conn.prepareStatement(sql);pstmt.setString(1, userId);pstmt.setString(2, password);rs = pstmt.executeQuery();if (rs.next()) {String realName = rs.getString("realname");int age = rs.getInt("age");user = new SysUser(userId, realName, password, age);}}catch (SQLException e) {e.printStackTrace();} finally {//6.关闭资源DBUtil.closeAll(rs, pstmt, conn);}return user;}@Overridepublic int save(SysUser user) {String sql = "insert into sys_user values(?, ?, ?, ?)";Object[] params = { user.getUserId(), user.getRealName(), user.getPwd(), user.getAge() };return DBUtil.executeUpdate(sql, params);}
}

3.5 在 servlet中使用

public class LoginServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8");// 接收用户编号和密码String username = req.getParameter("username");String pwd = req.getParameter("pwd");// 增加一个服务器端格式验证,验证数据合法性// ==================================== 访问数据库 ====================================UserDao userDao = new UserDaoImpl();SysUser sysUser = userDao.find(username, pwd);if (sysUser != null) {HttpSession session = req.getSession();session.setAttribute("user", sysUser);// 跳转到成功页面 【重定向 redirect】resp.sendRedirect(req.getContextPath() + "/login/success.jsp");} else {// 跳回登录页 【转发 dispatcher】req.setAttribute("error", "用户名或密码错误");req.getRequestDispatcher("/login/login.jsp").forward(req, resp);}}
}

3.6 在 JSP中处理

<%@ page import="com.lwclick.entity.SysUser" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title><%String basePath = request.getScheme() + "://" + request.getServerName() +":" + request.getServerPort() + request.getContextPath() + "/";%><base href="<%=basePath%>">
</head>
<body>欢迎您,<%SysUser user = (SysUser) session.getAttribute("user");out.println(user.getRealName());%>
</body>
</html>

4. MVC模式

分层思想:

  • 视图层view:Login.jsp success.jsp
  • 控制层control:LoginServlet
  • 数据访问层DAO:UserDao UserDaoImpl

4.1 提取业务层

为了条理清晰,减少 LoginServlet(control层)的操作,增加一个 业务层service,将所有涉及到业务的操作,都放在service中

4.2 JavaBean

符合特定规范的Java类,是一种可重用的组件

特定规范:

  • public class, 并且提供无参数构造方法
  • 属性private
  • 提供public的setter和getter方法

功能分类:

  • 封装数据:数据Bean --> 实体类
  • 封装业务:业务Bean --> service Dao

4.3 用户注册案例

register.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>用户注册</title><%String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";%><base href="<%=basePath%>">
</head>
<body>
<h3>注册用户</h3>
<form action="servlet/RegisterServlet" method="post"><table border="0" width="40%"><tr><td>用户编号</td><td><input  type="text" name="userId" id="userId" /></td></tr><tr><td>真实姓名</td><td><input  type="text" name="realName" id="realName"/></td></tr><tr><td>密&nbsp;码</td><td><input  type="password" name="pwd" id="pwd" /></td></tr><tr><td>确认密码</td><td><input type="password" name="repwd" id="repwd"/></td></tr><tr><td>年龄</td><td><input type="text"   name="age" id="age"/></td></tr><tr><td colspan="2"  align="center"><input  type="submit" value="提交"/><input type="reset" value="重置"/></td></tr></table>${error}
</form>
</body>
</html>

RegisterServlet.java

public class RegisterServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("utf-8");//1.接收视图层的表单数据String userId = request.getParameter("userId");String userName = request.getParameter("realName");String pwd = request.getParameter("pwd");String repwd = request.getParameter("repwd");//java.lang.NumberFormatException: For input string: "adfadf"int age = Integer.parseInt(request.getParameter("age")); //!!!  "23"  "adsfadf"// String [] hobbyArr = request.getParameterValues("hobby");///!!!//两次密码必须相同if(pwd == null || pwd.length()<=6 || !pwd.equals(repwd)){request.setAttribute("error", "密码长度必须大于6,两次密码必须相同");request.getRequestDispatcher("/register.jsp").forward(request, response);return;}//2.调用业务层完成注册操作User user = new User(userId, userName, pwd, age);UserService userService = new UserServiceImpl();int n  = userService.register(user);//3.根据注册结果进行页面跳转if(n > 0){//跳到登录页面(因为注册是添加操作,采用转发会导致表单重复提交)response.sendRedirect(request.getContextPath()+"/login/login.jsp");}else{// 因为要提示错误信息,所以需要使用 转发request.setAttribute("error", "注册失败");request.getRequestDispatcher("/register.jsp").forward(request, response);}}
}

UserService.java

public interface UserService {public int register(User user);
}

UserServiceImpl.java

public class UserServiceImpl implements UserService {private UserDao userDao = new UserDaoImpl();public UserDao getUserDao() {return userDao;}public void setUserDao(UserDao userDao) {this.userDao = userDao;}@Overridepublic int register(User user) {// UserDao userDao = new UserDaoImpl();int n = userDao.save(user);return n;}
}

UserDao.java

/*** Dao面对的是数据库,只有增删改查操作*/
public interface UserDao {public int save(User user);
}

UserDaoImpl.java

public class UserDaoImpl implements UserDao {@Overridepublic int save(User user) {String sql = "insert into user values(?,?,?,?)";Object params [] = {user.getUserId(), user.getUserName(), user.getPassword(), user.getAge()};return DBUtil.executeUpdate(sql, params);  // DBUtil 工具类是相同的}
}

4.4 合并Servlet

目前是以功能划分 servlet的,登录一个,注销一个,注册一个,现在将这 3个整合到一个 servlet中

第一种方式(不推荐):

  • UserServlet.java

    public class UserServlet extends HttpServlet {/*** 如果采用该种方法,表单必须是 post提交* 必须先解决 post表单的乱码问题,再接收表单数据* @param req* @param resp* @throws ServletException* @throws IOException*/@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8");// 获取请求中 method的值String method = req.getParameter("method");// 根据 method的值进行判断if ("login".equals(method)) {this.login(req, resp);} else if ("logout".equals(method)) {this.logout(req, resp);} else {this.register(req, resp);}}/*** RegisterServlet 注册的方法* @param req* @param resp*/public void register(HttpServletRequest req, HttpServletResponse resp) {// TODO}/*** LoginServlet 登录的* @param req* @param resp*/public void login(HttpServletRequest req, HttpServletResponse resp) {// TODO}/*** LogoutServlet 注销的* @param req* @param resp*/public void logout(HttpServletRequest req, HttpServletResponse resp) {// TODO}
    }
    
  • login.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><title>Title</title><%String basePath = request.getScheme() + "://" + request.getServerName() +":" + request.getServerPort() + request.getContextPath() + "/";%><base href="<%=basePath%>">
    </head>
    <body><!-- 修改action的路径,  action处有 ?,一定是 post提交方式 -->
    <form action="servlet/UserServlet?method=login" method="post">  </form>
    </body>
    </html>
    
  • success.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><title>Title</title><%String basePath = request.getScheme() + "://" + request.getServerName() +":" + request.getServerPort() + request.getContextPath() + "/";%><base href="<%=basePath%>">
    </head>
    <body><a href="servlet/UserServlet?method=logout">注销</a>
    </body>
    </html>
    

第二种方式:

  • BaseServlet.java

    /*** 不需要在 web.xml中进行配置*/
    public abstract class BaseServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 解决中文乱码req.setCharacterEncoding("utf-8");// 获取 method的值String methodName = req.getParameter("method");// 使用反射 !!!Class aClass = this.getClass();try {// Object obj = aClass.newInstance();  // 不能 new!!!不然违反 servlet的单实例Method aClassMethod = aClass.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);// 使用反射执行方法aClassMethod.invoke(this, req, resp);} catch (Exception e) {e.printStackTrace();}}
    }
    
  • UserServlet.java
    public class UserServlet extends BaseServlet {// 不再需要 service方法// 请求来了之后,去找父类的 service方法,通过反射,执行本类的方法// 页面处还是需要使用 ?method=XXX 去传递参数
    }
    

5. JSP高级内容

5.1 JSP执行原理

jsp --- 转译/翻译 --- Servlet --- 编译 --- class --- 执行
查看 JSP 转译之后的 Java文件

tomcat 的配置文件 web.xml

上图中的 JspServlet文件中的 service方法,最重要的两句话(在地址栏输入 xxxx.jsp后怎么转译、编译、解释执行的过程)

5.2 九大内建对象

  • response

    当服务器创建request对象时会同时创建用于响应这个客户端的response对象,程序员可往里放东西

  • out

    JspWriter 类的实例,不是PrinterWriter(在servlet.java中的out是)的实例

    JspWriter 增加了一些处理缓存的方法,并且会抛出 IOException 异常

  • pageContext

    用来代表整个JSP页面

Servlet 和 JSP 的联系和区别

JSP本质上是一个 Servlet

  • 联系

    • 都是动态网页技术
    • Servlet开发页面繁琐,推出JSP来简化页面开发
    • JSP本质上是一个Servlet,会翻译成一个Servlet
  • 区别
    • JSP使人们把显示和逻辑分隔开,意味着两者的开发可并行进行
    • Servlet需要在web.xml中配置,而JSP无需配置
    • JSP主要用在视图层负责显示,而Servlet主要用在控制层负责调度

5.3 四个作用域

在 jsp页面中使用,常用的方法都是 setAttribute()getAttribute()

  • page:当前页面 (一个页面)

    • 动态包含得不到 <jsp:include page=""></jsp:include>
    • 静态包含可以得到 <%@include file=""%>
  • request:当前请求 (一个请求的多个页面(多次转发) )

    • request = page + dipatcher转发 + include包含
    • 服务器端给了响应之后,客户端再发就是一个新的 request
  • session:当前会话 (一个用户的多个请求

    结束条件:

    • Session.invalidate()
    • 超过 MaxInactiveInterva l时间
    • 关闭浏览器(关闭后其实session还存在)
  • application:当前应用程序(一个应用的多个用户

    结束条件:

    • 重启服务器

6. JSTL/EL表达式

6.1 EL表达式

使用 ${} 在 JSP 页面中代替 getAttribute() 相关操作

${requestScope.error}: request 请求中的 error 字段 ====> 相当于 request.getAttribute(“error”)

EL的四个范围和JSP的四个范围对应,分别为pageContextScope、requestScope、sessionScope,applicationScope

如果未指定范围,则先从 pageContext范围开始找、然后找 request。。。

底层使用的是反射的机制,针对于对象的属性,使用的是 getter方法

6.2 JSTL表达式

使用 JSTL代替 JSP页面中的小脚本,声明,表达式等,全部是在服务器端执行的

JSTL的简单使用

声明变量 c:set :

<c:set var="sum" value="0"></c:set><!-- 相当于 -->
<%pageContext.setAttribute("sum", 0);
%>

判断是否为空值 empty :

<c:if test="${empty userList}"></c:if>

循环 map

<c:forEach items="${map}" var="entry">${entry.key} ---> ${entry.value}
</c:forEach>

6.3 有条件的查询用户信息

JSP页面

<%@ page import="com.bjsxt.entity.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html><head><title>Title</title><%String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";%><base href="<%=basePath%>"></head><body>登录成功!欢迎您:${sessionScope.user.userName}当前应用的历史访问人数:${applicationScope.count}<a href="servlet/UserServlet?method=logout">注销</a><hr><h3>用户列表</h3><hr><!-- 查询表单, 此处请求 find方法 --><form action="servlet/UserServlet?method=find" method="post"><table border="0" width="40%"><tr><td>用户编号</td><!-- ${userId} 用来获取页面转发后,request设置的数据,  数据回显 --><td><input  type="text" name="userId" id="userId" value="${userId}" /></td><td>年龄</td><td><input type="text"   name="age" id="age" value="${age}"/></td><td><input  type="submit" value="提交"/></td></tr></table></form><hr><table border="1" width="60%"><tr><th>用户账号</th><th>真实姓名</th><th>年龄</th><th>vs.index</th><th>vs.count</th><th>入学时间</th><th>爱好</th><th>操作</th></tr><c:if test="${empty requestScope.userList}"><tr><td colspan="10">一个学生也没有</td></tr></c:if><c:if test="${not empty requestScope.userList}"><!--1.循环之前定义sum、count,表示总年龄和人数 --><c:set var="sum" value="0" ></c:set><c:set var="count" value="0"></c:set><c:forEach items="${userList}" var="user" varStatus="vs"><!--2.循环过程中,实现年龄、人数的增加 --><c:set var="sum" value="${sum+user.age}"></c:set><c:set var="count" value="${count+1}"></c:set><tr <c:if test="${vs.index%2==0}">bgcolor="yellow"</c:if> ><td>${user.userId}</td><td>${user.userName}</td><td>${user.age}</td><td>${vs.index}</td><td>${vs.count}</td><td>${user.enterDate} ||  <fmt:formatDate value="${user.enterDate}" pattern="yyyy年MM月dd日"></fmt:formatDate> </td><td>${user.hobby}</td><td><a href="#">修改</a> <a href="#">删除</a></td></tr></c:forEach><!--3.循环之后,输出平均年龄、人数 --><tr><td colspan="10">总人数:${count}  平均年龄:${sum/count} ||<fmt:formatNumber value="${sum/count}" pattern="####.##" ></fmt:formatNumber>||<fmt:formatNumber value="${sum/count}" pattern="0000.00" ></fmt:formatNumber>||<fmt:formatNumber value="${sum/count}" pattern="¤0,000.00" ></fmt:formatNumber></td></tr></c:if></table></body>
</html>

Servlet.java

// 由 ` <a href="servlet/UserServlet?method=findAll">显示所有用户</a> `  发送请求
public void findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//接收来自视图层的数据(查询所有没有条件可以接收)//调用业务层查询所有的用户信息UserService userService = new UserServiceImpl();List<User> userList = userService.findAll(); // 业务层就是查询所有的操作,此处省略// 页面跳转request.setAttribute("userList", userList);request.getRequestDispatcher("/login/select.jsp").forward(request, response);
}// =================== 查询表单请求的 find 方法 ========================
public void find(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//接收来自视图层的数据String userId = request.getParameter("userId");String sage = request.getParameter("age");int age = 0;try {age = Integer.parseInt(sage);} catch (NumberFormatException e){e.printStackTrace();}//调用业务层查询所有的用户信息UserService userService = new UserServiceImpl();List<User> userList = userService.find(userId, age); // 业务层方法省略/**  业务层,根据 userId 和 age的有无,动态拼接 sqlStringBuilder sql = new StringBuilder("select  * from user where 1=1");      // 使用 1=1,后面统一跟 andif (cuserId != null && !"".equals(cuserId)) {sql.append(" and userid like '%" + cuserId + "%'");}if (cage > 0) {sql.append(" and age > " + cage);}sql.append(" order by age");*/// 页面跳转request.setAttribute("userList", userList);request.setAttribute("userId", userId);  // 回显输入的条件request.setAttribute("age", sage);request.getRequestDispatcher("/login/select.jsp").forward(request, response);
}

7. 过滤器

过滤器是驻留在服务器端的Web组件,它可以截取客户端和服务器目标资源之间的请求和响应信息,并对这些信息进行处理

过滤器是请求到达一个目标资源前的预处理程序,和/或响应离开目标资源后的后处理程序

应用:编码转化、数据过滤和替换、身份验证、数据加密、数据压缩、日志记录等

过滤器不仅要定义,也要在 web.xml 中配置,使用的是 职责链模式

7.1 解决中文乱码

EncodingFilter.java

public class EncodingFilter implements Filter {private String encoding;/*** 初始化操作,只执行一次* @param filterConfig* @throws ServletException*/@Overridepublic void init(FilterConfig filterConfig) throws ServletException {String encoding = filterConfig.getInitParameter("encoding");   // 从 web.xml中读取该文件的初始化参数if (encoding == null) {encoding = "utf-8";}}/*** 完成过滤操作,(过滤范围内的)每次请求响应都执行* @param servletRequest* @param servletResponse* @param filterChain* @throws IOException* @throws ServletException*/@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {// 请求到达之前的【预处理操作】servletRequest.setCharacterEncoding(encoding);// 将请求传递给下一个过滤器,或者目标资源filterChain.doFilter(servletRequest, servletResponse);// 响应离开目标资源之后的后处理操作}/*** 销毁操作,只执行一次*/@Overridepublic void destroy() {}
}

web.xml文件

<filter><filter-name>EncodingFilter</filter-name><filter-class>com.lwclick.filter.EncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param>
</filter>
<filter-mapping><filter-name>EncodingFilter</filter-name><url-pattern>/servlet/*</url-pattern>
</filter-mapping>

7.2 权限验证

AuthFilter.java

public class AuthFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;String requestURI = request.getRequestURI();String queryString = request.getQueryString();boolean flag1 = false;boolean flag2 = false;if (queryString != null) {flag1 = queryString.contains("method=login");flag2 = queryString.contains("method=register");}// 如果不是要排除在外的资源,进行验证(login.jsp、register.jsp、servlet/UserServlet?method=login、验证码等)if (!requestURI.contains("login.jsp") || !requestURI.contains("register.jsp")|| !flag1 || !flag2) {// 1. 预处理程序User user = (User) request.getSession().getAttribute("user");if (user == null) {// 未登录,转到登录页面response.sendRedirect(request.getContextPath() + "/login/login.jsp");return;}}// 2. 转到下一个过滤器或者目标资源filterChain.doFilter(request, response);}
}

web.xml

<filter><filter-name>AuthFilter</filter-name><filter-class>com.lwclick.filter.AuthFilter</filter-class>
</filter>
<filter-mapping><filter-name>AuthFilter</filter-name><url-pattern>/servlet/*</url-pattern><url-pattern>*.jsp</url-pattern>  <!-- 过滤jsp -->
</filter-mapping>

7.3 更多原理

多个过滤器,执行顺序怎么确定呢?

  • 最直观的就是在 web.xml中,谁的 filter-mapping 在前,谁先执行

每个请求和响应都要经过过滤器嘛?

  • 不是;只有请求路径和 filter-mapping 相匹配的请求

请求和响应时是不是分别将过滤器代码从头到尾执行一遍?

  • 不是;请求时执行预处理操作响应时执行后处理操作

在过滤器中能否跳转到项目的其他任意资源?

  • 可以;如果一个过滤器是进行权限验证,没有登录,就不让访问目标资源,直接跳转到login.jsp

重定向和转发是否经过过滤器?

  • 重定向经过

  • 转发默认不经过,因为是服务器端跳转。可以通过配置解决(在web.xml的 filter-mapping 中配置)

    <filter-mapping><filter-name>AuthFilter</filter-name><url-pattern>/servlet/*</url-pattern><url-pattern>*.jsp</url-pattern><dispatcher>REQUEST</dispatcher>   <!-- 请求经过过滤器(默认) --><dispatcher>FORWARD</dispatcher>   <!-- 配置【转发】也经过过滤器 -->
    </filter-mapping>
    

8. 监听器

8.1 作用及分类

作用

  • 监听Servlet容器中的事件。事件发生后,容器激活监听器,执行预定的操作

  • 监听的事件源分别为SerlvetConextHttpSessionServletRequest这三个域对象

    对应了JSP内建对象application、session、request对象上发生的事件

  • 可以在不修改现有系统基础上,增加web应用程序生命周期事件的跟踪

分类

  • 按监听的对象划分:servlet2.4规范定义的事件有三种

    • 监听应用程序环境对象 ServletContext 的(2个)
    • 监听用户会话对象 HttpSession 的(4个)
    • 监听请求消息对象(ServletRequest)的(2个)

按监听的 事件类项 划分

  • 监听域对象自身的创建和销毁的(3个) ---- 使用时必须在web.xm中注册

    • ServletRequestListener

    • HttpSessionListener

    • ServletContextListener

    • 均有两个方法(以ServletRequestListener举例)

      requestDestroyed(ServletRequestEvent sre) 对象【销毁】时

      requestInitialized(ServletRequestEvent sre) 对象【初始化】时

      <listener><listener-class>com.lwclick.listener.MyListener</listener-class>
      </listener>
      
    • 监听域对象中的属性的增加和删除的(3个) ---- 使用时必须在web.xm中注册

      • ServletRequestAttributeListener

      • HttpSessionAttributeListener

      • ServletContextAttributeListener

      • 均有三个方法(以ServletRequestListener举例)

        attributeAdded(ServletRequestAttributeEvent srae) setAttribute(‘error’, msg) 时

        attributeReplaced(ServletRequestAttributeEvent srae) setAttribute(‘error’, msg12) 同一个key,不同value时

        attributeRemoved(ServletRequestAttributeEvent srae) removeAttribute(‘error’) 时

    • 监听绑定到HttpSession域中的某个对象的状态的(2个) ---- 不需要在web.xml中注册,但是需要相应的类实现对应接口

      • 添加固定内容时(比如添加 setAttribute(“user”, user) 时 ),才触发事件

        需要 User 类实现 HttpSessionBindingListener 接口

      • 对象序列化到硬盘,或者反序列化到内存时,触发事件

        需要实现 HttpSessionActivationListenerSerializable 接口

        public class SysUser implements Serializable, HttpSessionBindingListener, HttpSessionActivationListener {@Overridepublic void valueBound(HttpSessionBindingEvent event) {System.out.println("----------- 绑定时 setAttribute ---------------");}@Overridepublic void valueUnbound(HttpSessionBindingEvent event) {System.out.println("----------- 解绑时 ---------------");}@Overridepublic void sessionWillPassivate(HttpSessionEvent se) {System.out.println("------------ 钝化:序列化到硬盘上 ------------");}@Overridepublic void sessionDidActivate(HttpSessionEvent se) {System.out.println("------------- 活化:反序列化到内存中 ------------");}
        }
        

    8.2 监听用户请求

    记录每个请求的时间、客户端IP、URL地址

    LogListener.java

    public class LogListener implements ServletRequestListener {@Overridepublic void requestDestroyed(ServletRequestEvent sre) {}@Overridepublic void requestInitialized(ServletRequestEvent sre) {PrintWriter printWriter = null;try {printWriter = new PrintWriter(new FileWriter("e:/sys.log"), true);// 时间Date date = new Date();// 客户端IPHttpServletRequest request = (HttpServletRequest) sre.getServletRequest();String ip = request.getRemoteAddr();// URL地址String url = request.getRequestURL().toString();String queryString = request.getQueryString();if (queryString != null) {printWriter.println(date + "\t" + ip + "\t" + url + "?" + queryString);} else {printWriter.println(date + "\t" + ip + "\t" + url);}} catch (IOException e) {e.printStackTrace();} finally {if (printWriter != null) {printWriter.close();}}}
    }
    

    web.xml

    <listener><listener-class>com.lwclick.listener.LogListener</listener-class>
    </listener>
    

    8.3 使用场合举例

    • 统计网站访问人数:只监听session开始
    • 在线用户检测:监听session开始和session结束
    • 网站登录用户人数:使用感知型监听器HttpSessionBindingListener监听用户对象放入session
    • 访问次数计数器:监听用户请求(因为图片等也进行请求,需要排除)
    • Web服务器的启动和停止:监听SerlvetConext的开始和结束
    • 会话结束后,下次打开购物车信息还在:使用感知型监听器监听session开始和结束
    • 项目启动时执行某些初始化操作(创建工厂和创建连接池):监听SerlvetConext的开始

【JavaLearn】(24)Session、Cookie、ServletContext、MVC开发模式、JSP九大内建对象及四个作用域、JSTL及EL表达式、过滤器、监听器相关推荐

  1. 小汤学编程之JavaEE学习day03——JSP组成结构、JSP原理、JSP生命周期、JSP九大内置对象、四大作用域、JSP的MVC模式

    一.JSP组成结构 二.JSP的原理 1.JSP的运行原理     2.分析JSP所生成的Servlet代码     3.JSP的执行过程 三.JSP生命周期 四.JSP九大内置对象 五.JSP四大作 ...

  2. JSP访问数据库,Session对象和九大内置对象

    文章目录 JSP访问数据库 Session对象 JSP九大内置对象 JSP访问数据库 JSP就是在HTML中嵌套的java代码,因此java代码可以卸载JSP中(<% - %>) 导包操作 ...

  3. 五、Web服务器——MVC开发模式 EL表达式 JSTL 学习笔记

    今日内容 1. JSP:1. 指令2. 注释3. 内置对象2. MVC开发模式 3. EL表达式 4. JSTL标签 5. 三层架构 JSP: 1. 指令* 作用:用于配置JSP页面,导入资源文件* ...

  4. java day41【JSP 、MVC开发模式 、EL表达式 、JSTL标签 、三层架构】

    第一章  JSP 1. 指令 * 作用:用于配置JSP页面,导入资源文件 * 格式: <%@ 指令名称 属性名1=属性值1 属性名2=属性值2 ... %> * 分类: 1. page : ...

  5. 方立勋_30天掌握JavaWeb_JavaBean、mvc开发模式、el表达式、jstl标签

    什么是JavaBean JavaBean是一个遵循特定写法的Java类,它通常具有如下特点: 这个Java类必须具有一个无参的构造函数 属性必须私有化. 私有化的属性必须通过public类型的方法暴露 ...

  6. 命名规范、MVC 开发模式

    一.高级软件介绍 JDK 7 Eclipse mars2 MySql Navicat 二.数据库 SQL 命令 1 创建数据库并指定编码 Create database 数据库名 default ch ...

  7. Re:PyQt5 从零开始的MVC开发模式规划

    前言 初次接触较大型的软件开发项目,找了几天可参照的项目无果,于是自己模仿django中的结构来做一个MVC开发模式规划,也有点闭门造车的意思,如有其他好的办法分享,下方评论见. (本篇文章从零开始, ...

  8. 面试题:什么是MVC开发模式,其优缺点。

    什么是MVC开发模式,其优缺点. 1.什么是MVC设计模式 MVC模式将系统分为视图,模型及控制器,其中控制器作用分离视图和模型,使系统解耦,易于修改和拓展,但同时增加了开发难度. 2.MVC优缺点 ...

  9. JavaWeb之MVC开发模式之商品实例CURD详解

    文章目录 三层MVC开发模式架构 一.先建立目标类对象:Curriculum. 三,过滤层Filter 四.增加商品 4.1 增加前端adds.jsp 4.2 增加的servlet服务 五.删除课程 ...

最新文章

  1. 最常用的css选择器及兼容性 +几个好用却不多见的 nth-child等
  2. 简单的TableViewCell高度自适应(只有Label,仅当参考思路)
  3. i386平台和x86-64平台机器代码的区别
  4. ubun16.04+搜狗输入法
  5. WP8.1使用HttpClient类
  6. 04.卷积神经网络 W4.特殊应用:人脸识别和神经风格转换(作业:快乐屋人脸识别+图片风格转换)
  7. 阿里 蚂蚁自研 IDE 研发框架 OpenSumi 正式开源
  8. java mvc 注解_Spring MVC注解开发入门
  9. java实现客服转接_Java微信公众平台开发(9) 关键字回复以及客服接口实现
  10. stm32F10x 看程序知识点记录
  11. 服务器隐藏盘符如何显示,Windows10系统如何使用注册表隐藏磁盘盘符?
  12. Ubuntu安装vbox(virtualbox)
  13. OpenCV_Find Basis F-Matrix and computeCorrespondEpilines(获取一对图像的基础矩阵及对应极线)
  14. sikuli python java_自动化测试之sikuli调研
  15. html图片加标题加链接,手机移动网页制作:插入图片、标题、文字链接
  16. linux-什么是Linux系统?linux详解Linux与Windows的区别Linux发行版本及特点介绍
  17. 路由器下设置局域网电脑共享
  18. 【总结】线性代数的本质 - 3
  19. 办公小技巧:excel纸张大小设置
  20. 利用python生成微信h5_Python + Appium 微信公众号 H5 页面自动化测试

热门文章

  1. 学习OpenCV双目测距原理及常见问题解答
  2. 计算机视觉笔记及资料整理(含图像分割、目标检测)
  3. 图像分割中CNN的简史:从R-CNN到Mask R-CNN
  4. 关于计算机英语演讲ppt模板,英语演讲ppt模板(英语演讲8分钟ppt模板) 最新免费版...
  5. centos 下载文件很慢_百度云盘上传文件和下载文件慢的解决办法
  6. 【论文笔记】RS--基于卫星遥感的中国县级尺度小麦估产研究
  7. android的aod的功能,一加正式推出氢OS 11:基于安卓11打造 新增「年轮AOD」功能
  8. django迁移数据makemigrations不创建APP中的数据表
  9. angular2 mysql_零起步学习angular2_angularjs教程_汇智网
  10. 通过SetWindowsHookEx实现跨进程子类化