pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>SpringBoot-login</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--SpringBoot Web启动-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--模板引擎 thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<scope>provided</scope>
</dependency>
<!--SpringBoot jdbc依赖包,使用 spring-boot-starter-jdbc 或 spring-boot-starter-data-jpa 将会自动获得HikariCP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--mybatis依赖包-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<!--mysql依赖包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--druid 德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<!--日志-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!--log4j日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--配置属性提示,有没有都没有关系-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--热部署环境配置包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<!--当前这个项目被继承之后,这个不向下传递-->
<optional>true</optional>
</dependency>
<!--定时器调度-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!--springboot redis整合-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--诺诺开票接口-->
<dependency>
<groupId>com.nuonuo</groupId>
<artifactId>open-sdk</artifactId>
<version>1.0.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
<!--解析base64流使用-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.0</version>
</dependency>
<!--httpClient URL-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.10</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
<!-- dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!-- XPath -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
<!--开源组件,做验证码-->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
<!--加密-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.4.2</version>
</dependency>
</dependencies>
<build>
<finalName>SpringBoot</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
application.yml
server:
port: 8090
# servlet:
# context-path: /zkc
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/zkc57?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
# thymeleaf配置文件
thymeleaf:
prefix: classpath:/templates/
check-template-location: true
suffix: .html
servlet:
content-type: text/html
mode: HTML
cache: false
mvc:
hiddenmethod:
filter:
enabled: true
jackson:
date-format: yyyy-MM-dd
time-zone: GMT+8
#热部署
devtools:
restart:
enabled: true
logging:
level:
com.shengun: debug
mybatis:
mapper-locations: classpath:/mapper/*.xml
type-aliases-package: com.shengun.*.entity
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
分为三个模块
user—login
User
package com.shengun.user.entity;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class User {
private int id;
private String username;
private String password;
private String chName;
}
UserMapper.xml
<?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.shengun.user.mapper.UserMapper">
<select id="getUser" parameterType="User" resultType="User">
select *
from t_user
where username = #{username};
</select>
</mapper>
mapper层
UserMapper
package com.shengun.user.mapper;
import com.shengun.user.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {
public User getUser(User user);
}
UserService
package com.shengun.user.service;
import com.shengun.user.entity.User;
public interface UserService {
public User login(User user);
}
UserServiceImpl
package com.shengun.user.service.impl;
import com.shengun.user.entity.User;
import com.shengun.user.mapper.UserMapper;
import com.shengun.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User login(User user) {
return userMapper.getUser(user);
}
}
UserController
package com.shengun.user.controller;
import com.shengun.user.entity.User;
import com.shengun.user.service.UserService;
import com.shengun.common.vo.Result;
import com.wf.captcha.utils.CaptchaUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/login")
public Result login(User param, String captcha, HttpServletRequest request,HttpSession session){
if (!CaptchaUtil.ver(captcha, request)) {
CaptchaUtil.clear(request); // 清除session中的验证码
return Result.fail("验证码不正确");
}
User user = userService.login(param);
if(user != null){
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
boolean matches = passwordEncoder.matches(param.getPassword(), user.getPassword());
if(matches){
user.setPassword(null);
session.setAttribute("userInfo",user);
return Result.success();
}
}
return Result.fail("用户名或者密码错误");
}
}
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录系统</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="Access-Control-Allow-Origin" content="*">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="format-detection" content="telephone=no">
<link rel="stylesheet" th:href="@{/layui/css/layui.css}" media="all">
<![endif]-->
<style>
html, body {width: 100%;height: 100%;overflow: hidden}
body {background: #1E9FFF;}
body:after {content:'';background-repeat:no-repeat;background-size:cover;-webkit-filter:blur(3px);-moz-filter:blur(3px);-o-filter:blur(3px);-ms-filter:blur(3px);filter:blur(3px);position:absolute;top:0;left:0;right:0;bottom:0;z-index:-1;}
.layui-container {width: 100%;height: 100%;overflow: hidden}
.admin-login-background {width:360px;height:300px;position:absolute;left:50%;top:40%;margin-left:-180px;margin-top:-100px;}
.logo-title {text-align:center;letter-spacing:2px;padding:14px 0;}
.logo-title h1 {color:#1E9FFF;font-size:25px;font-weight:bold;}
.login-form {background-color:#fff;border:1px solid #fff;border-radius:3px;padding:14px 20px;box-shadow:0 0 8px #eeeeee;}
.login-form .layui-form-item {position:relative;}
.login-form .layui-form-item label {position:absolute;left:1px;top:1px;width:38px;line-height:36px;text-align:center;color:#d2d2d2;}
.login-form .layui-form-item input {padding-left:36px;}
.captcha {width:60%;display:inline-block;}
.captcha-img {display:inline-block;width:34%;float:right;}
.captcha-img img {height:34px;border:1px solid #e6e6e6;height:36px;width:100%;}
#captchImg{
cursor: pointer;
}
</style>
</head>
<body>
<div class="layui-container">
<div class="admin-login-background">
<div class="layui-form login-form">
<form class="layui-form" action="">
<div class="layui-form-item logo-title">
<h1>LayuiMini后台登录</h1>
</div>
<div class="layui-form-item">
<label class="layui-icon layui-icon-username" for="username"></label>
<input type="text" name="username" lay-verify="required|account" placeholder="用户名或者邮箱" autocomplete="off" class="layui-input" value="zhangsan">
</div>
<div class="layui-form-item">
<label class="layui-icon layui-icon-password" for="password"></label>
<input type="password" name="password" lay-verify="required|password" placeholder="密码" autocomplete="off" class="layui-input" value="123456">
</div>
<div class="layui-form-item">
<label class="layui-icon layui-icon-vercode" for="captcha"></label>
<input type="text" name="captcha" lay-verify="required|captcha" placeholder="图形验证码" autocomplete="off" class="layui-input verification captcha" value="xszg">
<div class="captcha-img">
<img id="captchImg" th:src="@{/captcha}">
</div>
</div>
<div class="layui-form-item">
<input type="checkbox" name="rememberMe" value="true" lay-skin="primary" title="记住密码">
</div>
<div class="layui-form-item">
<button id="btn-login" class="layui-btn layui-btn layui-btn-normal layui-btn-fluid" lay-submit="" lay-filter="login">登 陆</button>
</div>
</form>
</div>
</div>
</div>
<script th:src="@{/js/jquery-3.4.1.js}" charset="utf-8"></script>
<script th:src="@{/layui/layui.js}" charset="utf-8"></script>
<script th:src="@{/js/jquery.particleground.min.js}" charset="utf-8"></script>
<script>
var ctxPath = "[[@{/}]]";
$("#captchImg").click(function (){
$("#captchImg").attr("src", ctxPath + "captcha?data=" + new Date().getTime())
});
layui.use(['form'], function () {
var form = layui.form,
layer = layui.layer;
// 登录过期的时候,跳出ifram框架
if (top.location != self.location) top.location = self.location;
// 粒子线条背景
$(document).ready(function(){
$('.layui-container').particleground({
dotColor:'#7ec7fd',
lineColor:'#7ec7fd'
});
});
// 进行登录操作
form.on('submit(login)', function (data) {
//防止多此登录
$("#btn-login").attr("disabled","disabled").addClass("layui-btn-disabled")
data = data.field;
if (data.username == '') {
layer.msg('用户名不能为空');
return false;
}
if (data.password == '') {
layer.msg('密码不能为空');
return false;
}
if (data.captcha == '') {
layer.msg('验证码不能为空');
return false;
}
var url = ctxPath + "user/login";
$.post(url,data,function (response){
console.log(response);
if(response.code == 0){
layer.msg('登录成功',{icon: 6,time: 1000}, function () {
window.location = ctxPath + 'index';
});
}else{
layer.msg(response.message,{icon:5,anim:6});
//恢复按钮
$("#btn-login").removeAttr("disabled","disabled").removeClass("layui-btn-disabled")
}
})
});
});
</script>
</body>
</html>
其中有个登录验证码
CommonController
package com.shengun.common.controller;
import com.wf.captcha.utils.CaptchaUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
public class CommonController {
@RequestMapping(value = {"","/login"})
public String login() {
return "login";
}
@RequestMapping("/index")
public String index() {
return "index";
}
@RequestMapping("/captcha")
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
CaptchaUtil.out(request, response);
}
}
登录图样式
登录成功
登录拦截器
LoginInterceptor
package com.shengun.common.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录拦截器
*/
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断session是否有信息
Object userInfo = request.getSession().getAttribute("userInfo");
if(userInfo == null){
//未登录
log.info("登录失败:" + request.getRequestURI());
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
log.info("登录成功:" + request.getRequestURI());
return true;
}
}
MyWebConfig
package com.shengun.common.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Autowired
@Qualifier("loginInterceptor")
private HandlerInterceptor handlerInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration registration = registry.addInterceptor(handlerInterceptor);
//拦截所有请求
registration.addPathPatterns("/**");
//资源放行
registration.excludePathPatterns(
"/login",
"/user/login",
"/emp/**",
//静态资源
"/css/**",
"/images/**",
"/js/**",
"/layui/**",
"/layuimin/**",
"/captcha"
);
}
}
emp—员工
Emp
package com.shengun.emp.entity;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
import java.util.Date;
@Data
@ToString
public class Emp implements Serializable {
private Integer empId;
private String name;
private String sex;
private Integer age;
private Double sal;
private Date birthday;
private String address;
private Integer deptId;
}
EmpController
package com.shengun.emp.controller;
import com.shengun.common.vo.Result;
import com.shengun.emp.entity.Emp;
import com.shengun.emp.service.EmpService;
import com.shengun.emp.vo.EmpQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("/emp")
public class EmpController {
@Autowired
private EmpService empService;
/**
* 查询员工数据接口
* name:
* startDate:
* endDate:
* page:
* limit:
* 示例:http://localhost:8090/emp/list?page=1&limit=10
* http://localhost:8090/emp/list?page=1&limit=10&name=李四
* http://localhost:8090/emp/list?page=1&limit=10&name=李四&startDate=2021-09-03
*/
@RequestMapping("/list")
@ResponseBody
public Result<Object> getEmpList(EmpQuery param){
System.out.println(param.getStartDate() + "====" + param.getEndDate());
List<Emp> empList = empService.getEmpList(param);
Long count = empService.countEmpList(param);
return Result.success(empList, count);
}
@RequestMapping("/empList")
public String empList(){
return "emp/empList";
}
}
EmpService
package com.shengun.emp.service;
import com.shengun.emp.entity.Emp;
import com.shengun.emp.vo.EmpQuery;
import java.util.List;
public interface EmpService {
public List<Emp> getEmpList(EmpQuery param);
Long countEmpList(EmpQuery param);
}
EmpServiceImpl
package com.shengun.emp.service.impl;
import com.shengun.emp.entity.Emp;
import com.shengun.emp.mapper.EmpMapper;
import com.shengun.emp.service.EmpService;
import com.shengun.emp.vo.EmpQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
@Override
public List<Emp> getEmpList(EmpQuery param) {
return empMapper.getEmpList(param);
}
@Override
public Long countEmpList(EmpQuery param) {
return empMapper.countEmpList(param);
}
}
EmpMapper
package com.shengun.emp.mapper;
import com.shengun.emp.entity.Emp;
import com.shengun.emp.vo.EmpQuery;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface EmpMapper {
public List<Emp> getEmpList(EmpQuery param);
Long countEmpList(EmpQuery param);
}
EmpMapper.xml
<?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.shengun.emp.mapper.EmpMapper">
<!--查询员工列表的数据-->
<select id="getEmpList" parameterType="com.shengun.emp.vo.EmpQuery" resultType="Emp">
select * from t_emp
<include refid="getEmplistWhere"></include>
limit #{start}, #{limit}
</select>
<!--查询员工列表的数量-->
<select id="countEmpList" parameterType="com.shengun.emp.vo.EmpQuery" resultType="Long">
select count(1) from t_emp
<include refid="getEmplistWhere"></include>
</select>
<sql id="getEmplistWhere">
<where>
<if test="name != null">
name like '%' #{name} '%'
</if>
<if test="startDate != null">
<![CDATA[
and birthday >= #{startDate}
]]>
</if>
<if test="endDate != null">
<![CDATA[
and birthday <= #{endDate}
]]>
</if>
</where>
</sql>
</mapper>
Page
package com.shengun.common.vo;
import lombok.Data;
@Data
public class Page {
private Integer page;
private Integer limit;
public Long getStart(){
return (page - 1L) * limit;
}
}
EmpQuery
package com.shengun.emp.vo;
import com.shengun.common.vo.Page;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Data
public class EmpQuery extends Page {
private String name;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date endDate;
}