[Javaweb 05] MVC,过滤器实现未登录时保护某些页面不能访问
MVC,过滤器实现未登录时保护某些页面不能访问
1. MVC三层架构
MVC: Model View Controller 模型, 视图,控制器
1. 早期模型
servlet(包括CRUD代码)---> 数据库
弊端: 程序不利于维护
servlet的代码中: 处理请求,响应,视图跳转,处理JDBC、业务代码,处理逻辑代码等
2. MVC模型
View:
- 展示数据
- 给用户提供链接,用于发起Servlet请求
Controller: (Servlet)
- 接收用户的请求req(请求参数,Session信息)
- 交给业务层处理对应的代码
- 控制视图的跳转
Model:
- 业务处理:业务逻辑(Service层)
- 数据持久层: CRUD(Dao层)
例子:
登录页面, 接收用户的登录请求(View)
处理用户的请求,如登录参数,username, psw(Controller也是Servlet)
交给业务层处理登录业务,判断密码是否正确(Model_业务层)
Dao查询数据库中的用户名密码是否正确(Model_Dao层)
2. Filter过滤器
用来过滤网站的数据, 如: 每个servlet在调用前都先调用处理中文乱码,登录验证过滤等。
过滤器中的方法doFilter(Request, Response, FilterChain)
实际应用中,过滤器不止一个,可以连接多个过滤器,所以在doFilter方法中,必须要写chain自己的方法。
1. 写类实现Filter接口
public class CharacterEncodingFilter implements Filter {
// init方法在web服务器启动时就调用,需要随时监听需要过滤的页面
public void init(FilterConfig filterConfig) throws ServletException {}
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");
//必须写,让请求继续走,(可能有别的过滤器), 如果不写,程序被拦截
filterChain.doFilter(servletRequest, servletResponse);
}
// web服务器关闭的时候,才调用销毁
public void destroy() {}
}
2. 在web.xml文件中配置
servlet文件:配置servlet和servlet-mapping, 在mapping时,配置两个路径:
<servlet></servlet>
<servlet-mapping>/show</servlet-mapping>
<servlet-mapping>/servlet/show</servlet-mapping>
filter文件: 路径配置含义: 过某个路径下的所有文件都走这个过滤器:
<filter></filter>
<filter-mapping>
<filter-name>filterName</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
当servlet走/show
路径时,不经过过滤器,显示乱码
当servlet走/servlet/show
路径时,经过过滤器,显示正常
3. Listener 监听器
去实现Listner的接口,很多lister接口,看需求实现
统计在线人数:
1. 实现listener接口:
// 涉及监听者模式
public class OnlineCountListener implements HttpSessionListener {
//每创建一个session,就调用一次这个方法
public void sessionCreated(HttpSessionEvent se) {//se代表session事件的对象
ServletContext ctx = se.getSession().getServletContext();
Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
if (onlineCount == null){
onlineCount = new Integer(1);
}else{
int count = onlineCount.intValue();
onlineCount = new Integer(count +1);
}
ctx.setAttribute("OnlineCount", onlineCount);
}
//每销毁一个session, 就调用一次
public void sessionDestroyed(HttpSessionEvent se) {
// 销毁代码相反,数量 --;
}
}
2. web.xml配置
<listener>
<listener-class>包.类</listener-class>
</listener>
去前端实现显示人数
4. Filter实现权限拦截(登录监听)
重点总结:
- 后端文件中,
/
表示当前项目的根目录,在页面跳转至中,如果在web目录下,直接用/文件名.jsp
访问。其他的也按照文件目录或映射来走。一定要注意目录跳转!!!! - 页面中,用户信息一般放在Session中,方便跳转或者重定向的时候携带数据过去。
- 可以在util包中创建一个Constant类,放置常用到的数据名称,如:session中的key值,以便于管理
- Constant类中定义的变量必须是public的!你吃了大亏
实现某些页面未登录无法直接访问到
1. 项目目录:
2. 前端界面
index.jsp和error.jsp在项目目录下,登入和登出界面需要保护,放在sys目录下
1. 登入界面 index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="/servlet/login" method="post">
<input type="text" name="userName">
<input type="submit">
</form>
</body>
</html>
2. 错误界面 error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
错误
<a href="index.jsp">登录</a>
</body>
</html>
3. 登入成功界面 succession.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
成功登录<br>
<a href="/servlet/logout">登出</a>
</body>
</html>
4. 登出成功界面 logoutSuccession.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
登出成功!
<a href="index.jsp">登录</a>
</body>
</html>
3. 业务代码:
业务代码都是servlet类,放入servlet包中
1. Login.java
public class Login extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String userName = req.getParameter("userName");
if("admin".equals(userName)){
req.getSession().setAttribute("USER_SESSION", req.getSession().getId());
resp.sendRedirect("/sys/succession.jsp");
}else{
resp.sendRedirect("/error.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2. Logout.java
public class Logout extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object user_session = req.getSession().getAttribute("USER_SESSION");
if(user_session!=null){
req.getSession().removeAttribute("USER_SESSION");
resp.sendRedirect("/index.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
4. 过滤器代码
过滤器都实现filter接口,放在filter包下
1. 中文乱码解决
public class CharacterChange implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
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");
filterChain.doFilter(servletRequest,servletResponse);//重要,必须写,否则页面中断
}
public void destroy() {}
}
2. Sys文件夹保护
public class SysDirectorFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
if (req.getSession().getAttribute("USER_SESSION") == null){
resp.sendRedirect("/index.jsp");
}
filterChain.doFilter(servletRequest,servletResponse);//重要,必须写,否则页面中断
}
public void destroy() {}
}
5. web.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.roy.servlet.Login</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/servlet/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>logout</servlet-name>
<servlet-class>com.roy.servlet.Logout</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>logout</servlet-name>
<url-pattern>/servlet/logout</url-pattern>
</servlet-mapping>
<!-- 字符串 过滤器-->
<filter>
<filter-name>character</filter-name>
<filter-class>com.roy.Filter.CharacterChange</filter-class>
</filter>
<filter-mapping>
<filter-name>character</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
<!-- sys资源过滤器-->
<filter>
<filter-name>sysFilter</filter-name>
<filter-class>com.roy.Filter.SysDirectorFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sysFilter</filter-name>
<url-pattern>/sys/*</url-pattern>
</filter-mapping>
</web-app>
6. 改进添加的Util包中的 Constant类
public class Constant{
//方便常用值的维护,如在session中get/set其中的key时,直接调用 Constant.USER_SESSION
public final static String USER_SESSION = "USER_SESSION";
}