🥼JavaWeb~(伍)架构,filter,listener,demo.
笔记代码
MVC 架构
Model 模型 view 视图 Controller 控制 三方分离的架构
之前的架构:
- Servlet 直接进行 CRUD 操作,程序比较臃肿,不利于维护
于是,为了解决这种不便利性,再加一层! (没有什么是加一层解决不了的)
各部分的职责:
Model
业务处理 :业务逻辑(Service)
数据持久层:CRUD (Dao - 数据持久化对象)
View
展示数据
提供链接发起 Servlet 请求 (a,form,img…)
Controller (Servlet)
接收用户的请求 :(req:请求参数、Session 信息….)
交给业务层处理对应的代码
控制视图的跳转 (转发/重定向)
一条流程:
View 层点击登录 --> 接收用户的登录请求 --> 处理用户的请求(获取用户登录的参数,username,password)–> 交给业务层处理登录业务(判断用户名密码是否正确:操作事务)–> Dao 层查询用户名和密码是否正确 --> 数据库
顺利查询到数据之后就是反过来再进行数据传递
中间层工具
常见的有
过滤器 filter
,监听器 listener
,拦截器 Interceptor
下面介绍 filter(重点) 和 listener
Filter 过滤器
介绍
比如处理中文乱码,敏感词汇,登录验证
…
例子: 比如 Shiro 安全框架技术就是用 Filter 来实现的
导入依赖
老四样:
<!-- servlet依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- JSP依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!-- JSTL表达式依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Standard标签库 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>之后好像还会用到 SQL 驱动依赖,到时候在说.
filter 例子
src/main/java/filter/CharacterEncodingFilter.java
package filter;
import javax.servlet.*;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
//初始化并等待过滤对象出现
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharacterEncodingFilter初始化");
}
/*
1. 过滤中的所有代码,在过滤特定请求的时候都会执行
2. 必须要让过滤器继续执行 (因为filter可能不止一个,需要传递)
chain.doFilter(request,response);
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
System.out.println("CharacterEncodingFilter执行前....");
chain.doFilter(request, response); //让我们的请求继续走,如果不写,程序到这里就被拦截停止!
System.out.println("CharacterEncodingFilter执行后....");
}
//销毁:web服务器关闭的时候,过滤器会销毁
public void destroy() {
System.out.println("CharacterEncodingFilter销毁");
}
}src/main/java/servlet/Show.java
package servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Show extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 通过filter实现处理乱码
resp.getWriter().write("你好!");
}
}web.xml
配置 servlet 和 filter
|
监听器
- 对应不同业务需求,存在 N 中不同的监听器接口可供实现.
- 监听器经常在 GUI 编程中使用.
例子: 设置 session 监听器监听有多少 session 连接
src/main/java/listener/OnlineCountListener.java
package listener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
//统计网站在线人数 -> 统计session
public class OnlineCountListener implements HttpSessionListener {
private ServletContext ctx;
private Integer onlineCount;
//一旦创建Session就会触发一次这个事件
public void sessionCreated(HttpSessionEvent se) {
initParam(se);
ctx.setAttribute("OnlineCount", ++onlineCount);
}
/*
一旦销毁Session就会触发一次这个事件
Session销毁:
1. 手动销毁 getSession().invalidate();
2. 自动销毁
*/
public void sessionDestroyed(HttpSessionEvent se) {
initParam(se);
ctx.setAttribute("OnlineCount", --onlineCount);
}
public void initParam(HttpSessionEvent se) {
ctx = se.getSession().getServletContext();
onlineCount = (Integer) ctx.getAttribute("OnlineCount");
if (onlineCount == null) {
ctx.setAttribute("OnlineCount", 0);
}
}
}index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>在线人数测试</title>
</head>
<body>
<h1>当前有 <span
style="color: turquoise;"><%=this.getServletConfig().getServletContext().getAttribute("OnlineCount")%></span> 人在线
</h1>
</body>
</html>注册监听器
<!--注册监听器-->
<listener>
<listener-class>listener.OnlineCountListener</listener-class>
</listener>
GUI 编程例子
GUI 编程常会用到监听器,这里简单介绍一下 :
src/main/java/listener/TestPanel.java
package listener;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class TestPanel {
public static void main(String[] args) {
Frame frame = new Frame("Hello World!"); //新建一个窗体
Panel panel = new Panel(null); //面板
frame.setLayout(null); //设置窗体的布局
frame.setBounds(300, 300, 500, 500);
frame.setBackground(new Color(0, 0, 255)); //设置背景颜色
panel.setBounds(50, 50, 300, 300);
panel.setBackground(new Color(0, 255, 0)); //设置背景颜色
frame.add(panel);
frame.setVisible(true);
//监听事件,监听关闭事件
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
登录验证 demo
项目结构,如图:
JSP 页面
主页(登录页面):
web/demo/index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主页</title>
</head>
<body>
<h1>登录</h1>
<form action="${pageContext.request.contextPath}/demo/login" method="post">
<label>
用户名:
<input type="text" name="username"/>
</label>
<input type="submit" value="登录">
</form>
</body>
</html>
登陆失败:
web/demo/failed.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录失败</title>
</head>
<body>
<h1>登录失败进入的页面</h1>
<a href="${pageContext.request.contextPath}/demo/index.jsp">返回主页</a>
</body>
</html>
登录成功:
web/demo/sys/success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>已登录</title>
</head>
<body>
<h1>登录成功后进入的页面</h1>
<hr>
<a href="${pageContext.request.contextPath}/demo/logout">注销</a>
</body>
</html>
Java 后端
login:
src/main/java/demo/servlet/Login.java
package demo.servlet;
import demo.utils.Constants;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class Login extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
this.doPost(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String username = req.getParameter("username");
HttpSession session = req.getSession();
if (username.equals("admin")) {
session.setAttribute(Constants.USER_SESSION, session.getId());
resp.sendRedirect("/demo/sys/success.jsp");
} else {
resp.sendRedirect("/demo/failed.jsp");
}
}
}
注销:
src/main/java/demo/servlet/Logout.java
package demo.servlet;
import demo.utils.Constants;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class Logout extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
Object attribute = session.getAttribute(Constants.USER_SESSION);
/*
频繁操作session连接会影响性能,通过attribute间接验证登录信息
通过设置或移除 USER_SESSION 属性来验证是否登录
存在一个Bug: 在注销状态通过浏览器的后退,可以返回登陆成功的页面(且不存在USER_SESSION)
*/
if (attribute != null) {
session.removeAttribute(Constants.USER_SESSION);
resp.sendRedirect("/demo/index.jsp");
}
}
提取的常量工具类:
src/main/java/demo/utils/Constants.java
package demo.utils;
/**
* 此类内定义一些其他各种地方需要经常调用的常量
*/
public class Constants {
public final static String USER_SESSION = "USER_SESSION";
}
过滤器类:
src/main/java/demo/filter/SysFilter.java
package demo.filter;
import demo.utils.Constants;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SysFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
Object attribute = req.getSession().getAttribute(Constants.USER_SESSION);
if (attribute == null) {
resp.sendRedirect("/demo/failed.jsp");
}
chain.doFilter(request, response);
}
public void destroy() {
}
}
Web.xml
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>demo.servlet.Login</servlet-class>
</servlet>
<servlet>
<servlet-name>logout</servlet-name>
<servlet-class>demo.servlet.Logout</servlet-class>
</servlet>
<filter>
<filter-name>sysFilter</filter-name>
<filter-class>demo.filter.SysFilter</filter-class>
</filter>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/demo/login</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>logout</servlet-name>
<url-pattern>/demo/logout</url-pattern>
</servlet-mapping>
<filter-mapping>
<filter-name>sysFilter</filter-name>
<url-pattern>/demo/sys/*</url-pattern>
</filter-mapping>