Java Web登录功能完整实现:详解MVC分层与权限控制
·
MVC 分层思想(解耦:高内聚低耦合)
controller层
- 接收请求
(调用service层,返回结果)
- 响应结果
service层
- 业务逻辑判断
mapper
- 接口类
mapper.xml mybatis与数据库的相关操作
entity(po、model)
- JavaBean实体
util
- 工具类(通用的方法/类)
test
- 测试类/方法
优点:
-
耦合性低
视图层和业务层分离,允许更改视图层代码而不用重新编译模型和控制器代码。 -
重用性高
多个视图能共享一个模型,如电脑和手机访问同一服务。 -
开发效率提高,人员职责明确
Java 开发人员专注于业务逻辑,界面开发人员专注于表现形式。 -
耦合度低,可维护性高
每层代码修改可达到无损替换效果。 -
有利软件工程化管理
每层职责明确,便于工具化管理。
分层思想案例
页面完成登录功能,登录成功跳转到项目首页,登录失败提示信息。
用户登录思路分析
用户登录
1.数据库创建对应的用户表 tb user
2.前台页面
登录页面 login.jsp
用户登录 JS校验
1.给登录按钮绑定点击事件
2.获取用户姓名和密码的值
3.判断姓名是否为空
如果姓名为空,提示用户(span标签赋值),并且return
4.判断密码是否为空
如果密码为空,提示用户(span标签赋值),并且return
5.如果都不为空,则手动提交表单
首页 index.jsp
3.后代实现
登录功能
思路:
1.接收客户端的请求(接收参数:姓名、密码)
2.参数的非空判断
如果参数为空
通过消息模型对象返回结果(设置状态、设置提示信息、回显数据)
将消息模型对象设置到request作用域中
请求转发跳转到登录页面
return
3.通过用户姓名查询用户对象
4.判断用户对象是否为空
如果为空
通过消息模型对象返回结果(设置状态、设置提示信息、回显数据)
将消息模型对象设置到request作用域中
请求转发跳转到登录页面
return
5.将数据库中查询到的用户密码与前台传递的密码作比较
如果不相等
通过消息模型对象返回结果(设置状态、设置提示信息、回显数据)
将消息模型对象设置到request作用域中
请求转发跳转到登录页面
如果相等,表示登录成功
将用户信息设置到session作用域中
重定向跳转到首页
controller层(接收请求、响应结果)
1.接收客户端的请求(接收参数:姓名、密码)
2.调用service层的方法,返回消息模型对象
3.判断消息模型的状态码
如果状态码是失败
将消息模型对象设置到request作用域中,请求转发跳转到1ogin.jsp
如果状态码是成功
将消息模型中的用户信息设置到session作用域中,重定向跳转到index.jsp
service层(业务逻辑判断)
1.参数的非空判断
如果参数为空
将状态码、提示信息、回显数据设置到消息模型对象中,返回消息模型对象
2.调用dao层的查询方法,通过用户名查询用户对象
3.判断用户对象是否为空
如果为空,将状态码、提示信息、回显数据设置到消息模型对象中,返回消息型对象
4.判断数据库中查询到的用户密码与前台传递过来的密码作比较
如果不相等,将状态码、提示信息、回显数据设置到消息模型对象中,返回消息模型对象
5.登陆成功,将成功状态、提示信息、用户对象设置消息模型对象,并return
mapper层(Dao层)
定义对应的接口
项目实现
【1】创建数据库表
CREATE TABLE t_user (
uid INT PRIMARY KEY,
uname VARCHAR(255),
pwd VARCHAR(255)
);
【2】创建项目,并导入 jar 包
项目结构:
LoginProject
├── src
│ ├── com.rito.controller
│ │ └── LoginServlet
│ ├── com.rito.dao
│ │ ├── UserDao
│ │ └── impl
│ │ └── UserDaoImpl
│ ├── com.rito.pojo
│ │ └── User
│ ├── com.rito.service
│ │ ├── UserService
│ │ └── impl
│ │ └── UserServiceImpl
│ └── Main
├── web
│ ├── WEB-INF
│ │ ├── lib
│ │ │ ├── jsp-api.jar
│ │ │ ├── jstl.jar
│ │ │ ├── mysql-connector-java-8.0.11.jar
│ │ │ ├── servlet-api.jar
│ │ │ └── standard.jar
│ │ └── web.xml
│ ├── index.jsp
│ └── login.jsp
└── LoginProject.iml
【3】登录页面实现:login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<div style="text-align:center">
<form action="loginServlet" method="post">
用户名: <input type="text" name="uname"><br>
密码: <input type="password" name="pwd"><br>
<input type="submit" value="登录"><br>
${failmsg}
</form>
</div>
</body>
</html>
【4】实体类 User.java
package com.msb.pojo;
public class User {
private int uid;
private String uname;
private String pwd;
// 构造方法、getter/setter、toString 略
}
/**消息模型对象(数据响应)
src
│ ├── com.rito.pojo
│ │ └── vo
│ │ └── MessageModel
│ │ └── User
* 状态码
* 1=成功,0=失败
* 提示信息
* 字符串
* 回显数据
* objecty象
*/
public class MessageModel {
private Integer code=1;//状态码(1=成功,0=失败)
private String msg ="成功!";// 提示信息
private Object object;// 回显对象 (基本数据类型、字符串类型、List、Map等)
// 构造方法、getter/setter、toString 略
}
【5】Servlet 实现:LoginServlet.java
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uname = req.getParameter("uname");
String pwd = req.getParameter("pwd");
UserDao userDao = new UserDao();
User user = userDao.selectOne(uname, pwd);
if (user != null) {
resp.sendRedirect(req.getContextPath() + "/index.jsp");
} else {
req.setAttribute("failmsg", "登录失败");
req.getRequestDispatcher("/login.jsp").forward(req, resp);
}
}
}
【6】DAO 层:
UserDao.java
public class UserDao {
User selectOneUser(String uname, String pwd);
}
UserDaoImpl.java
public class UserDaoImpl implements UserDao {
public User selectOneUser(String uname, String pwd) {
// JDBC 查询数据库,返回 User 对象
}
}
【7】Service 层
UserService.java
public interface UserService {
User selectUserInfo(String uname, String pwd);
}
UserServiceImpl.java
public class UserServiceImpl implements UserService {
UserDao userDao = new UserDaoImpl();
public User selectUserInfo(String uname, String pwd) {
return userDao.selectOneUser(uname, pwd);
}
}
过滤器(Filter)
基本概念
- 定义:
Filter是 Servlet 规范中的一种组件,用于在 Servlet 之外对Request或Response进行修改 - 作用时机:
- 对用户请求进行预处理
- 对服务器响应进行后处理
- 过滤器链:多个 Filter 组合形成链式处理
- 请求时:按配置顺序执行
- 响应时:按相反顺序执行
生命周期方法
public interface Filter {
void init(FilterConfig filterConfig); // 初始化
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain); // 过滤处理
void destroy(); // 销毁
}
步骤
- 编写 Java 类实现 Filter 接口,并实现其
doFilter()方法 - 通过编写
@WebFilter("/*")注解设置它所能拦截的资源
核心机制
FilterChain.doFilter(request,response):决定是否放行请求到下一个过滤器或目标资源- 调用
doFilter():请求到达目标资源 - 不调用
doFilter():拦截请求,资源无法被访问
- @WebFilter("/s01”)配置拦截的资源路径
- doFilter()方法中需要设置放行,否则请求无法到达资源( filterchain,dofilter(request,response)😉
- 如果是过滤器链,则先配置的先执行(首字母在前的先执行);响应时顺序反过来
过滤器应用场景
- 身份认证和授权检查
- 日志记录和审计
- 数据压缩和加密
- 字符编码转换
- 输入验证和XSS防护
过滤器实例
请求乱码处理
@WebFilter("/*")//拦截所有
public class AEncodingFilter implements Filter {
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException {
//基于HTTP
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
// 处理POST请求乱码
request.setCharacterEncoding("UTF-8");
// 处理GET请求(Tomcat8以下版本)
String method = request.getMethod();
if ("GET".equalsIgnoreCase(method)) {
String serverInfo = request.getServletContext().getServerInfo();
//得到具体的版本号
String versionStr = serverInfo.substring(serverInfo.indexOf("/")+1, serverInfo.indexOf("."));
//判断服务器版本是否小于8
if (Integer.parseInt(versionStr) < 8) {
//得到自定义类 (MyWapper继承了HttpservletRequestWapper对象,而HttpservletRequestWapper对象实现了HttpservletRequest接口,所以Mywapper的本质也是request对象)
HttpServletRequest myRequest = new MyMapper(request);
chain.doFilter(myRequest, response);
return;
}
}
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {}
/**
* 定义内部类,继承HttpServletRequestWrapper包
装类对象,重写getParameter()方法
*/
class MyWapper extends HttpServletRequestWrapper {
// 定义成员变量,提升构造器 中的request对象的范围
private HttpServletRequest request;
public MyWapper(HttpServletRequest request) {
super(request);
this.request = request;
}
/**
* 重写getParameter()方法
*/
@Override
public String getParameter(String name) {
String value = request.getParameter(name);
if (value != null && !"".equals(value.trim())) {
try {
// 将默认ISO-8859-1编码的字符转换成UTF-8
value = new
String(value.getBytes("ISO-8859-1"),"UTF-8");
} catch(UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return value;
}
}
}
用户非法访问拦截
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 非法访问拦截(当用户未登录时,拦截请求到登录页面)
* 拦截的资源:
* 拦截所有资源 /*
* 需要被放行的资源:不需要登录即可访问的资源
* 1、放行指定页面,不需要登录可以访问的页面(例如:登录页面、注册页面等)
* 2、放行静态资源(例如:css、js、image等资源)
* 3、放行指定操作,不需要登录即可执行的操作(例如:登录操作、注册操作等)
* 4、登录状态放行 (如果存在指定sessuin对象,则为登录状态)
*
* 其他请求需要被拦截跳转到登录界面
*/
@WebFilter("/*")
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException {
// 基于HTTP
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
// 得到请求的路径
String path = request.getRequestURI(); // 站点名/资源路径
// 1、放行指定页面,不需要登录可以访问的页面(例如:登录页面、注册页面等)
if (path.contains("/login.jsp") || path.contains("/register.jsp")) {
chain.doFilter(request, response);
return;
}
// 2、放行静态资源(例如:css、js、image等资源)
if (path.contains("/js")) {
chain.doFilter(request, response);
return;
}
// 3、放行指定操作,不需要登录即可执行的操作(例如:登录操作、注册操作等)
if (path.contains("/loginServlet")) {
chain.doFilter(request, response);
return;
}
// 4、登录状态放行 (如果存在指定sessuin对象,则为登录状态)
// 得到session域对象
String uname = (String) request.getSession().getAttribute("user");
// 如果session域对象不为空,则为登录状态,放行资源
if (uname != null && !"".equals(uname.trim())) {
chain.doFilter(request, response);
return;
}
// 若以上条件均不满足,拦截跳转到登录页面
response.sendRedirect("login.jsp");
return;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化方法,可以留空
}
@Override
public void destroy() {
// 销毁方法,可以留空
}
}
监听器(Listener)
分类(三类8种)
监听生命周期
ServletRequestListener:监听Request对象的创建和销毁HttpSessionListener:监听Session对象的创建和销毁ServletContextListener:监听Application对象的创建和销毁
监听值的变化
ServletRequestAttributeListener:监听Request域中属性的变化HttpSessionAttributeListener:监听Session域中属性的变化ServletContextAttributeListener:监听Application域中属性的变化
针对Session中的对象
- 监听Session中的JavaBean对象
监听器应用场景
- 统计在线用户数
- 系统初始化工作
- 统计网站访问量
- 监听用户行为
- 资源清理工作
在线人数统计实例
@WebListener
public class OnlineListener implements HttpSessionListener {
private Integer onlinenumber = 0;
@Override
public void sessionCreated(HttpSessionEvent se) {
onlinenumber++;
// 存储到application作用域
se.getSession().getServletContext().setAttribute("onlinenumber", onlinenumber);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
onlinenumber--;
se.getSession().getServletContext().setAttribute("onlinenumber", onlinenumber);
}
}
更多推荐

所有评论(0)