个人博客-1(登录功能模块实现)

前言

前端页面基于 AdminLTE3 模板进行开发的。
下载地址:https://github.com/ColorlibHQ/AdminLTE/releases

声明:该项目是GitHub上的开源项目,本人已购买作者相关课程,仅供个人学习使用。
课程链接https://www.lanqiao.cn/courses/1367

用到的技术

  • springboot
  • thymeleaf
  • lombok
  • ajax
  • kaptcha(验证码功能)

AdminLTE3 模板整合

新建一个springboot项目

在这里插入图片描述

添加web启动器和thymeleaf启动器及lombok

  • 后续需要其他功能了再添加对应的依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

整合AdminLTE3 模板

整合过程其实是我们把 AdminLTE3 代码压缩包中我们需要的样式文件、js 文件、图片等静态资源放入我们 Spring Boot 项目的静态资源目录下,比如 static 目录或者其他我们设置的静态资源目录,几个重要的文件我们都在下图中用红线进行标注了,目录如下:
在这里插入图片描述

后台管理模块

登录功能模块

数据库和表设计

注意点

  • 插入数据的时候就使用md5加密,密码字段要设计的大点
-- 新建一个数据库
CREATE DATABASE `rm_blog`;

USE `rm_blog`;

-- 新建一个adminUser表
DROP TABLE IF EXISTS `admin_user`;

CREATE TABLE `admin_user`(
	`id` INT(8) NOT NULL AUTO_INCREMENT COMMENT'用户id',
	`user_name` VARCHAR(20) NOT NULL COMMENT'用户姓名',
	`password` VARCHAR(50) NOT NULL COMMENT'用户密码', -- 使用md5加密,该字段要设计的长点
	`nick_name` VARCHAR(20) COMMENT'显示在浏览器界面的用户名',
	`locked` TINYINT(4) DEFAULT '0' COMMENT'该用户是否锁定,0未锁',
	PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;


INSERT INTO `admin_user`VALUES(1,'rm',MD5('123456'),'初夏那片海',0);

在这里插入图片描述

实体类

根据数据库创建对应的实体类

  • 实际项目可以看情况是否使用lombok插件
  • 使用基本类型包装类创建属性
import lombok.Data;

@Data
public class AdminUser {
    //使用基本类型包装类
    private Integer id;
    private String userName;
    private String password;
    private String nickName;
    private Byte locked;

}

application.yaml

  • 开启驼峰命名
mybatis:
  configuration:
    map-underscore-to-camel-case: true #开启驼峰命名

dao层

导入mybatis-springboot依赖

  • 声明mapper,配置mybatis
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>

AdminUserMapper

@Mapper //表明是一个Mapper,也可以通过扫描包的方式实现
@Repository //注入spring容器
public interface AdminUserMapper {
    //根据用户名和密码进行登录 @Param后面的值是从前端页面接收的值
    AdminUser login(@Param("userName") String userName,@Param("password") String password);
}

AdminUserMapper.xml

  • 密码使用md5加密处理
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.rm.dao.AdminUserMapper">
    <select id="login" resultType="adminUser">
        select * from admin_user where user_name=#{userName} and password=md5(#{password});
    </select>

</mapper>

application.yaml

  • 开启别名
  • 开启mapper路径映射
mybatis:
  type-aliases-package: com.rm.pojo #别名扫描包
  mapper-locations: /mapper/*.xml

sercice层

调用dao层
AdminUserService

@Service
public interface AdminUserService {

    AdminUser login(@Param("userName") String userName, @Param("password") String password);
}

AdminUserServiceImpl

@Service
public class AdminUserServiceImpl implements AdminUserService {

    @Autowired
    private AdminUserMapper adminUserMapper;


    @Override
    public AdminUser login(String userName, String password) {
        return adminUserMapper.login(userName,password);
    }
}

验证码功能

验证码配置

配置验证码颜色,字体,长度等属性
KaptchaConfig

package com.rm.config;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;

//验证码配置类
@Configuration
public class KaptchaConfig {
    @Bean
    public DefaultKaptcha getDefaultKaptcha(){
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 图片边框
        properties.put("kaptcha.border", "no");
        // 字体颜色
        properties.put("kaptcha.textproducer.font.color", "blue");
        // 图片宽
        properties.put("kaptcha.image.width", "160");
        // 图片高
        properties.put("kaptcha.image.height", "40");
        // 字体大小
        properties.put("kaptcha.textproducer.font.size", "30");
        // 验证码长度
        properties.put("kaptcha.textproducer.char.length", "4");
        // 字体
        properties.setProperty("kaptcha.textproducer.font.names", "宋体,微软雅黑");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}
验证码生成

生成验证码并保存到session中

package com.rm.controller.common;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;

//验证码Controller
//生成验证码并保存到session中
@Controller
@RequestMapping("/common")
public class KaptchaController {

    @Autowired
    private DefaultKaptcha captchaProducer;

    @GetMapping("/kaptcha")
    public void defaultKaptcha(
            HttpServletRequest request,
            HttpServletResponse response) throws Exception {

        byte[] captchaOutputStream;
        ByteArrayOutputStream imgOutputStream = new ByteArrayOutputStream();
        try {
            //生产验证码字符串并保存到session中
            String verifyCode = captchaProducer.createText();
            request.getSession().setAttribute("verifyCode", verifyCode);
            BufferedImage challenge = captchaProducer.createImage(verifyCode);
            ImageIO.write(challenge, "jpg", imgOutputStream);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        captchaOutputStream = imgOutputStream.toByteArray();
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = response.getOutputStream();
        responseOutputStream.write(captchaOutputStream);
        responseOutputStream.flush();
        responseOutputStream.close();
    }

}

controller层

AdminUserController

import com.rm.pojo.AdminUser;
import com.rm.service.AdminUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpSession;

@Controller
@RequestMapping("/admin")  
public class AdminController {

    //注入AdminUserService
    @Autowired
    private AdminUserService adminUserService;

    //请求方式是get时,解析到login页面
    @GetMapping({"/login"})
    public String login() {
        return "admin/login";
    }

	//登录成功,重定向到首页
    @GetMapping({"/index","/index.html"})
    public String index() {
        return "admin/index";
    }

    //请求方式是post时,验证验证码是否输入正确
    @PostMapping("/login")
    public String login(@RequestParam("userName") String userName,
                        @RequestParam("password") String password,
                        @RequestParam("verifyCode") String verifyCode,
                        HttpSession session) {
        if (StringUtils.isEmpty(verifyCode)) {
            session.setAttribute("errorMsg", "验证码不能为空");
            return "admin/login";
        }
        if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(password)) {
            session.setAttribute("errorMsg", "用户名或密码不能为空");
            return "admin/login";
        }
        String kaptchaCode = session.getAttribute("verifyCode") + "";
        if (StringUtils.isEmpty(kaptchaCode) || !verifyCode.equals(kaptchaCode)) {
            session.setAttribute("errorMsg", "验证码错误");
            return "admin/login";
        }

        AdminUser adminUser = adminUserService.login(userName, password);
        System.out.println("adminUser========="+adminUser);

        if (adminUser != null) {
        	//将登录的用户信息保存到session中
            session.setAttribute("loginUser", adminUser);
            session.setAttribute("loginUserId", adminUser.getId());
            //session过期时间设置为7200秒 即两小时
            session.setMaxInactiveInterval(60 * 60 * 2);
            return "redirect:/admin/index";
        } else {
            session.setAttribute("errorMsg", "用户名或密码错误");
            return "admin/login";
        }
    }
}

前端

login.html

<!DOCTYPE html>
<!--导入thymeleaf约束-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Rm Blog登录页</title>
  <!--告诉浏览器响应屏幕的宽度-->
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <!--导入样式文件-->
  <!--该页面的favicon(static目录能自动识别)-->
  <link rel="shortcut icon" th:href="@{/admin/dist/img/favicon.ico}" />
  <!-- 字体样式 -->
  <link rel="stylesheet" th:href="@{/admin/dist/css/font-awesome.min.css}" />
  <!-- 图标样式 -->
  <link rel="stylesheet" th:href="@{/admin/dist/css/ionicons.min.css}" />
  <!-- 主题样式 -->
  <link rel="stylesheet" th:href="@{/admin/dist/css/adminlte.min.css}" />

</head>

<body class="hold-transition login-page">

<!--登录框-->
<div class="login-box">

  <!--rm blog-->
  <div class="login-logo" style="color: #007bff;">
    <h1>rm blog</h1>
  </div>

  <!-- /.login-logo -->
  <div class="card">
    <div class="card-body login-card-body">
      <p class="login-box-msg">请登录</p>

      <!--表单提交到后台/login请求-->
      <form th:action="@{/admin/login}" method="post">
        <div
                th:if="${not #strings.isEmpty(session.errorMsg)}"
                class="form-group"
        >
          <div
                  class="alert alert-danger"
                  th:text="${session.errorMsg}"
          ></div>
        </div>

        <div class="form-group has-feedback">
          <span class="fa fa-user form-control-feedback"></span>
          <input
                  type="text"
                  id="userName"
                  name="userName"
                  class="form-control"
                  placeholder="请输入账号"
                  required="true"
          />
        </div>
        <div class="form-group has-feedback">
          <span class="fa fa-lock form-control-feedback"></span>
          <input
                  type="password"
                  id="password"
                  name="password"
                  class="form-control"
                  placeholder="请输入密码"
                  required="true"
          />
        </div>
        <div class="row">
          <div class="col-6">
            <input
                    type="text"
                    class="form-control"
                    name="verifyCode"
                    placeholder="请输入验证码"
                    required="true"
            />
          </div>
          <div class="col-6">
            <img
                    alt="单击图片刷新!"
                    class="pointer"
                    th:src="@{/common/kaptcha}"
                    onclick="this.src='/common/kaptcha?d='+new Date()*1"
            />
          </div>
        </div>
        <div class="form-group has-feedback"></div>
        <div class="row">
          <div class="col-8"></div>
          <div class="col-4">
            <button
                    type="submit"
                    class="btn btn-primary btn-block btn-flat"
            >登录
            </button>
          </div>
        </div>
      </form>
    </div>
  </div>
</div>

<!-- jQuery -->
<script src="@{/admin/plugins/jquery/jquery.min.js}"></script>
<!-- Bootstrap 4 -->
<script src="@{/admin/plugins/bootstrap/js/bootstrap.bundle.min.js}"></script>
<script th:src="@{/admin/dist/js/plugins/particles.js}"></script>
<script th:src="@{/admin/dist/js/plugins/login-bg-particles.js}"></script>

</body>
</html>

测试登录

在这里插入图片描述

登录成功跳转到主页

在这里插入图片描述
至此,简单的登录模块就完成了。接下来就需要配置登录拦截器,不登录的用户无法访问到主页。

登录拦截器

前面简单的实现了登陆功能,本节将会对功能进行完善,对后台资源请求进行身份认证,即请求拦截验证。

定义拦截器

package com.rm.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component //添加到spring容器
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
     HttpServletResponse response, Object handler) throws Exception {
     
        String uri = request.getRequestURI();
        if (uri.startsWith("/admin") && null == request.getSession().getAttribute("loginUser")) {
            request.getSession().setAttribute("errorMsg", "请重新登陆");
            response.sendRedirect(request.getContextPath() + "/admin/login");
            return false;
        } else {
            request.getSession().removeAttribute("errorMsg");
            return true;
        }

    }

    @Override
    public void postHandle(HttpServletRequest request, 
    HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, 
    HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

配置拦截器

MvcConfig

package com.rm.config;

import com.rm.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//SpringMvc配置类
@Configuration
public class MvcConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    public void addInterceptors(InterceptorRegistry registry) {
        // 添加一个拦截器,拦截以/admin为前缀的url路径
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/admin/**")  //拦截以/admin为前缀的url路径
                .excludePathPatterns("/admin/login")  //放行登录页
                .excludePathPatterns("/admin/dist/**") //放行静态资源
                .excludePathPatterns("/admin/plugins/**"); //放行静态资源
    }

}

未登录状态下/admin以下的所有请求都会被拦截,除了登录页

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值