其他分享
首页 > 其他分享> > 使用Servlet实现用户登录功能,并使用过滤器防止用户未登录直接访问管理员后台页面

使用Servlet实现用户登录功能,并使用过滤器防止用户未登录直接访问管理员后台页面

作者:互联网

使用Servlet实现用户登录功能,并使用过滤器防止用户未登录直接访问管理员后台页面

1、连接数据库(两种方式)

  第一种:读取数据库配置文件,获得数据库连接

    (1)创建数据库配置文件(database.properties)

        

     

    (2)util包创建配置文件管理类(ConfigManage)

package cn.kgc.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
 * @author J
 * 读取数据库配置文件,获取数据库连接信息
 * 如何让用户只能创建一个ConfigManage?单例模式!1、把构造方法设为私有 2、程序提供给用户唯一一个对象
 * 单例模式的两种实现方式:
 * 懒汉方式(线程不安全):类名.调用getInstance静态方法时,再new ConfigManage对象,保证只能new一个对象
 * 饿汉方式(线程安全):不管调不调用getInstance方法,都只会new一个ConfigManage对象
 */
public class ConfigManage {
    //声明私有的静态ConfigManage对象 单例模式:懒汉方式(线程不安全)
    private static ConfigManage configManage;
    //创建私有的静态ConfigManage对象,只要加载ConfigManage类到JVM,就要加载静态代码,就会new ConfigManage对象 单例模式:饿汉方式(线程安全)
    //private static ConfigManage configManage = new ConfigManage();
    //声明私有的properties对象
    private Properties properties;
    /**
     * 无参构造方法
     */
    private ConfigManage(){
        //定义配置文件的名称
        String configFile = "database.properties";
        //配置文件通过ConfigManage类加载器的getResourceAsStream方法将资源读到输入流里面
        InputStream inputStream = ConfigManage.class.getClassLoader().getResourceAsStream(configFile);
        //创建Properties类型的对象
        properties = new Properties();
        try {
            //输入流加载到properties对象中
            properties.load(inputStream);
            //释放资源
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 单例模式:懒汉方式(线程不安全)可加同步锁解决线程不安全问题
     * 提供给用户唯一一个ConfigManage对象
     * @return
     * 为什么用static修饰?
     * 1、如果不用static修饰,用户会new ConfigManage对象调用getString方法
     * 但是无参构造定义为私有的,new不了ConfigManage对象,也就调不了getString方法
     * 2、用static修饰,静态方法可以类名.直接调用getInstance方法
     * 如果ConfigManage对象为空,则new一个ConfigManage对象;如果ConfigManage对象不为空,return返回
     * 以此保证用户只能new一个ConfigManage对象
     */
    public static synchronized ConfigManage getInstance(){
        if(configManage == null){
            configManage = new ConfigManage();
        }
        return configManage;
    }

    /**
     * 单例模式:饿汉方式(线程安全)
     * 不管调不调用getInstance方法,都只会new一个ConfigManage对象
     * @return
     */
    /*public static ConfigManage getInstance(){
        return configManage;
    }*/

    /**
     * 根据配置文件中的键获得对应的值
     * @param key
     * @return
     */
    public String getString(String key){
        return properties.getProperty(key);
    }
}

 

    (3)创建数据库操作基类(BaseDao)获得数据库连接

/**
 * @author J
 * 数据库操作基类
 */
public class BaseDao {
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    /**
     * 获得数据库连接
     * @return
     */
    public boolean getConnection(){
        try {
            //1、加载MySQL数据库厂商提供的驱动
            Class.forName(ConfigManage.getInstance().getString("driver"));
            //2、建立数据库连接Connection
            String url = ConfigManage.getInstance().getString("url");
            String user = ConfigManage.getInstance().getString("user");
            String password = ConfigManage.getInstance().getString("password");
            connection= DriverManager.getConnection(url,user,password);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
            return false;
        }
        return true;

    }
    /**
     * 释放资源 先开后关
     * @return
     */
    public boolean closeResource(){
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                return false;
            }
        }
        if(preparedStatement != null){
            try {
                preparedStatement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                return false;
            }
        }
        if(connection != null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                return false;
            }
        }
        return true;
    }
}

  

  第二种:JNDI方式创建数据源(DataSource),获得数据库连接

    (1)首先要配置数据源的相关连接信息,也就是数据源连接池。该配置应该在Tomcat安装目录下的conf/context.xml文件中配置。配置如下:

 

 

     

    (2)创建数据库基类(BaseDao)获得数据库连接

/**
 * @author J
 * 数据库操作基类
 */
public class BaseDao {
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
   /**
     * 通过数据源获得数据库连接
     * @return
     */
    public boolean getConnection2(){
        try {
            //初始化上下文对象
            Context context = new InitialContext();
            //获取与逻辑名称相关联的数据源对象
            DataSource dataSource = (DataSource) context.lookup("java:comp/env/jdbc/news");
            //通过数据源获取数据库连接
            connection = dataSource.getConnection();
        } catch (NamingException | SQLException e) {
            e.printStackTrace();
        }
        return true;

    }
    /**
     * 释放资源 先开后关
     * @return
     */
    public boolean closeResource(){
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                return false;
            }
        }
        if(preparedStatement != null){
            try {
                preparedStatement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                return false;
            }
        }
        if(connection != null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                return false;
            }
        }
        return true;
    }
}

 

2、pojo包编写用户信息的实体类

package cn.kgc.pojo;

/**
 * @author J
 * @Date 2021/10/9 2:19
 * 封装用户信息的实体类(也就是封装数据的JavaBean)
 */
public class User {
    /**
     * 定义私有的成员属性(对应数据表news_user中的字段)
     */
    private String userName ;
    private String password;

    /**
     * 创建公有的getter/setter方法,用于属性的读写
     * @return
     */
    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

 

3、编写公用的查询方法(BaseDao)

/**
     * 查询方法
     * @param sql 因为查询要有SQL语句,所以将SQL语句作为参数
     * @param params 因为不确定SQL语句中占位符?的个数,所以将数组params作为参数;不确定填充占位符?的参数类型,所以数组类型为Object类型
     * @return 返回值类型是ResultSet 结果集
     */
    public ResultSet executeQuery(String sql,Object[] params){
        //获得数据库连接
        if(this.getConnection()){
            try {
                //创建PreparedStatement对象发送SQL语句到数据库执行
                preparedStatement = connection.prepareStatement(sql);
                //for循环遍历params数组 数组长度=占位符的个数
                for(int i = 0; i < params.length; i++){
                    //填充占位符?  key,value  在第几个?,数组下标为几的值
                    preparedStatement.setObject(i+1,params[i]);
                }
                //获得ResultSet结果集
                resultSet = preparedStatement.executeQuery();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        return resultSet;
    }

 

4、编写用户信息数据操作的接口(UserDao)

package cn.kgc.dao;

import cn.kgc.pojo.User;

/**
 * @author J
 * @Date 2021/10/9 10:51
 * 用户信息数据操作的接口
 */
public interface UserDao {
    /**
     * 根据用户名和去数据库查询有没有该用户
     * @param userName
     * @return
     */
    public User getUserByInfo(String userName);
}

 

5、实现用户信息数据操作接口(UserDaoImpl)

package cn.kgc.dao.impl;

import cn.kgc.dao.BaseDao;
import cn.kgc.dao.UserDao;
import cn.kgc.pojo.User;

import java.sql.ResultSet;

/**
 * @author J
 * @Date 2021/10/9 22:15
 * 用户信息操作接口的实现类
 */
public class UserDaoImpl extends BaseDao implements UserDao {
    /**
     * 根据用户名和密码去数据库查询有没有该用户
     * @param userName
     * @return
     */
    @Override
    public User getUserByInfo(String userName) {
        //创建User对象
        User user = new User();
        try {
            //编写SQL语句
            String sql = "SELECT * FROM news_user WHERE userName = ?";
            //定义Object类型的数组Params并将参数赋值
            Object[] params = {userName};
            //调用executeQuery()方法传入参数(sql语句,params数组) 返回results结果集
            ResultSet resultSet = this.executeQuery(sql,params);
            //处理执行结果
            while (resultSet.next()){
                //把在数据库查询到的用户名和密码赋值给user对象
                user.setUserName(resultSet.getString("userName"));
                user.setPassword(resultSet.getString("password"));
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        } finally {
            //释放资源
            this.closeResource();
        }
        return user;
    }
}

 

6、编写用户信息业务逻辑操作的接口(UserService)

package cn.kgc.service;

import cn.kgc.pojo.User;

/**
 * @author J
 * @Date 2021/10/9 23:19
 * 用户信息业务逻辑操作的接口
 */
public interface UserService {
    /**
     * 登录判断
     * @param userName
     * @param password
     * @return
     */
    public int judgeLogin(String userName,String password);
}

 

7、实现用户信息业务逻辑操作接口(UserServiceImpl)

package cn.kgc.service.impl;

import cn.kgc.dao.UserDao;
import cn.kgc.dao.impl.UserDaoImpl;
import cn.kgc.pojo.User;
import cn.kgc.service.UserService;

/**
 * @author J
 * @Date 2021/10/9 23:23
 * 用户信息业务逻辑操作接口的实现类
 */
public class UserServiceImpl implements UserService {
    /**
     * 登录判断
     * @param userName
     * @param password
     * @return
     */
    @Override
    public int judgeLogin(String userName, String password) {
        //初始化登录失败
        int i = 0;
        //如果用户名和密码是空/NULL 登录失败
        if(userName == "" || userName == null || password == "" || password == null){
            return i;
        }
        //实例化UserDao接口的实现类
        UserDao userDao = new UserDaoImpl();
        //调用userDao.getUserByInfo()方法,将表单提交的userName作为参数,返回user对象
        User user = userDao.getUserByInfo(userName);
        //判断:如果表单提交的密码与user对象中的密码不相同,登录失败;否则登录成功。
        if(!password.equals(user.getPassword())){
            i = 0;
        }else {
            i = 1;
        }
        return i;
    }
}

 

8、编写处理用户登录的Servlet

package cn.kgc.web.servlet;

import cn.kgc.pojo.News;
import cn.kgc.pojo.User;
import cn.kgc.service.NewsService;
import cn.kgc.service.UserService;
import cn.kgc.service.impl.NewsServiceImpl;
import cn.kgc.service.impl.UserServiceImpl;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * 处理用户登录的Servlet:
 * 接收用户表单提交的用户名和密码,去数据库查有没有这个用户。如果有,跳转到首页。如果没有,跳转到登录失败页面。
 *
 * Servlet:接收请求,调用JavaBean处理请求
 */
@WebServlet(name = "AddServlet")
public class LoginServlet extends HttpServlet {
    /**
     * 处理Post请求
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //实例化User对象
        User user = new User();
        //获取用户表单提交的用户名、密码
        String userName = request.getParameter("userCode");
        String password = request.getParameter("userPassword");
        //实例化userService接口的实现类
        UserService userService = new UserServiceImpl();
        //调用userService.judgeLogin()方法,将表单提交的用户名和密码作为参数,返回int类型的值
        int i = userService.judgeLogin(userName,password);
        //若i>0,则登录成功;否则登录失败。
        if(i > 0){
            System.out.println("登录成功!");
            //将表单提交的用户名和密码赋值给user对象
            user.setUserName(userName);
            user.setPassword(password);
            //把use对象放进session作用域里面,考虑到其他页面也可能用到用户信息
            request.getSession().setAttribute("user",user);
            //重定向跳转到首页 绝对路径 相对于整个Web应用
            response.sendRedirect("/news/jsp/admin/admin.jsp");
        } else {
            System.out.println("登录失败!请点击返回跳转到登录页面");
            //重定向跳转到登录失败页面
            response.sendRedirect("/news/jsp/error.jsp");
        }
    }

    /**
     * 处理Get请求
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //不管是Get请求还是Post请求,Servlet针对一个请求只做一个响应。如果是Get请求,调用doPost()方法,如果是Post请求,直接进doPost()方法
        this.doPost(request,response);
    }
}

 

9、web.xml中配置LoginServlet

<!--创建LoginServlet实例-->
    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>cn.kgc.web.servlet.LoginServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/servlet/LoginServlet</url-pattern>
    </servlet-mapping>

 

 

10、前台登录页面(login.jsp)

 <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<script type="text/javascript">
    function validate(){
        //验证
        var userCode = document.getElementById("userCode").value;
        var userPassword = document.getElementById("userPassword").value;
        var userCodeSpan = document.getElementById("userCodeSpan");
        var userPasswordSpan = document.getElementById("userPasswordSpan");
        var flag = true;
        if(userCode == null  || userCode == ''){
            userCodeSpan.innerHTML = "请输入用户名";
            flag = false;
        }
        if(userPassword == null || userPassword == ''){
            userPasswordSpan.innerHTML = "请输入密码";
            flag = false;
        }
        //提交
        var actionForm = document.getElementById("actionForm");
        if(flag){
            actionForm.submit();
        }
        
    }
  </script>


<body>
        <form  action="${pageContext.request.contextPath }/servlet/LoginServlet"  name="actionForm" id="actionForm"  method="post" >
            <dl>
                <dt>用户名:</dt>
                <dd><input type="text" id="userCode" name="userCode"/> <span id="userCodeSpan"></span> </dd>
                <dt>密 码:</dt>
                <dd><input type="password"  id="userPassword" name="userPassword"/><span id="userPasswordSpan"></span></dd>
            </dl>
            <div class="buttons">
                ${error }
                <input type="button"   value="登录系统" onclick="validate();" />
                <input type="reset"  value="重  填" class="input-button" />
            </div>
        </form>


</body>
</html>

 

11、启动服务器,浏览器访问http://localhost:8080/news/jsp/login.jsp 进入登录页面

 

如果直接点登录,前台JavaScript非空验证提醒

 

 若表单输入的用户名和密码与数据库中news_user表的数据不匹配,则登录失败进入error.jsp,点击返回跳转到登录页面

 

 若表单输入的用户名和密码与数据库中news_user表的数据匹配,登录成功,跳转到首页

 

 截至目前,登录功能已完成。

存在问题:如果用户不登录而直接访问http://localhost:8080/news/jsp/admin/admin.jsp管理员页面呢?是可以直接访问到,但如何避免这种情况的发生?

回答:使用过滤器防止用户未登录直接访问管理员后台页面

1、编写用户登录的过滤器(LoginFilter)

package cn.kgc.web.filter;

import cn.kgc.pojo.User;

import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author J
 * @Date 2021/10/10 3:17
 * 用户登录的过滤器
 */
public class LoginFilter implements Filter {
    /**
     * 初始化方法
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    /**
     * 销毁方法
     */
    @Override
    public void destroy() {

    }

    /**
     * 实现过滤行为
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //判断用户是否登录-->判断session中是否有用户
        //首先将servletRequest和servletResponse强转为HttpServletRequest和HttpServletResponse
        HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;
        //获得当前request中的HttpSession,通过建(user)拿到对应的值,返回值类型是Object类型。将Object类型强转为User类型
        User user = (User)httpServletRequest.getSession().getAttribute("user");
        //判断:若对象为null,重定向跳转到error页面,绝对路径。若对象不为null,调用下一个过滤器或Web资源
        if(user == null){
            httpServletResponse.sendRedirect("/news/jsp/error.jsp");
        } else {
            filterChain.doFilter(servletRequest,servletResponse);
        }

    }
}

 

2、web.xml中配置LoginFilter

 <!--配置LoginFilter-->
    <filter>
        <!--过滤器名-->
        <filter-name>LoginFilter</filter-name>
        <!--过滤器的完全限定名-->
        <filter-class>cn.kgc.web.filter.LoginFilter</filter-class>
    </filter>

    <filter-mapping>
        <!--过滤器映射名-->
        <filter-name>LoginFilter</filter-name>
        <!--过滤器映射的Web资源-->
        <url-pattern>/jsp/admin/*</url-pattern>
    </filter-mapping>

3、重新启动服务,浏览器直接访问http://localhost:8080/news/jsp/admin/admin.jsp管理员页面,就会重定向跳转到失败页面(error.jsp),解决了用户未登录直接访问管理员后台页面的问题。若用户输入正确的用户名和密码,则可以进入系统的首页。

 

 

 

      

      

      

 

 

  

标签:ConfigManage,return,cn,登录,用户,kgc,import,Servlet,public
来源: https://www.cnblogs.com/mimi123118/p/15388442.html