从头开始,基于springboot的web登录详细登录实现。
创建springboot项目
工欲善其事,必先利其器。下面就和我一起轻扣IDEA的大门,新建一个springboot项目。
- 打开IDEA,点击file—new—project开始创建一个新项目。
- 选择spring Initializr,然后默认选项next
- 按图填写自己的项目信息然后next
- 选择spring web 然后next
- 选择项目存放路径,然后点击 Finish。等待片刻
- 等待IDEA构建好项目后,项目结构如下图所示。
web项目功能集成
-
配置项端口8088
在application.properties文件中添加server.port=8088
注意:如果pom文件没有项目打包方式会导致修改端口无效。在pom文件中加入jar就可以解决。
2. 集成lombox
2.1 在pom文件中添加jar包
<!--集成lombox-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2.2 安装lombox插件
2.3 使用lombox编写User类。
package com.yangpeng.logindemo.models;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.util.Date;
@Getter
@Setter
@ToString
public class User implements Serializable {
private static final long serialVersionUID = 68403886070098162L;
private Integer uid;
private String userName;
private String passWord;
private String realName;
private Date updateTime;
}
- 集成Thymeleaf模板引擎
3.1 在pom文件中添加jar包
<!--集成Thymeleaf模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
3.2 在application.properties文件中加入配置
# thymeleaf
#视图存放的位置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.check-template-location=true
#网页的后缀名
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=utf-8
spring.thymeleaf.content-type=text/html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.cache=false
3.3创建测试类
@Controller
@RequestMapping("/test")
public class TestController {
@Autowired
private IUserService userService;
@RequestMapping("/user")
public String getUser(Model model) {
User user = new User();
user.setUid(1);
user.setUserName("yangpeng");
user.setRealName("杨朋");
user.setUpdateTime(new Date());
model.addAttribute("user", user);
return "userInfo";
}
}
3.4 创建页面userInfo
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form>
<input type="text" hidden="hidden" th:field="${user.uid}" />
<textarea th:field="${user.userName}"></textarea>
<textarea th:field="${user.passWord}"></textarea>
<textarea th:field="${user.realName}"></textarea>
<textarea th:field="${user.updateTime}"></textarea>
</form>
</body>
</html>
3.5页面模板引擎集成完成,效果如下
4. 集成MySQL+mybatis
4.1 添加mysql和mybatis依赖的jar包
<!--集成mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!--集成mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
4.2 添加mysql配置
#MySQL数据库的简单设置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/login?Unicode=true&characterEncoding=utf-8&useAffectedRows=true&serverTimezone=GMT&allowMultiQueries=true
spring.datasource.username=yangpeng
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#设置等待数据库的最大连接数量,0表示没有限制
spring.datasource.tomcat.max-idle=10
#设置连接数据库最大活动数量
spring.datasoure.tomcat.max-active=100
#设置最大的等待毫秒数,超出报错
spring.datasoure.tomcat-wait=10000
#设置数据库连接初始化的连接池数量
spring.datasource.tomcat.initial-size=5
4.3添加mybatis配置
#配置映射文件存放位置
mybatis.mapper-locations=classpath:mapper/*.xml
#扫描别名
mybatis.type-aliases-package=com.yangpeng.logindemo.models
#打开二级缓存,默认一级缓存是打开的
mybatis.configuration.cache-enabled=true
4.4写一个测试用例
4.4.1 编写dao
package com.yangpeng.logindemo.dao;
import com.yangpeng.logindemo.models.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserDao {
User getUserByUid(Integer uid);
int insert(User user);
User getUserByUserName(String userName);
}
4.4.2编写dao对应的mapper
<?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.yangpeng.logindemo.dao.UserDao">
<resultMap id="BaseResultMap" type="com.yangpeng.logindemo.models.User">
<result column="id" jdbcType="INTEGER" property="uid" />
<result column="userName" jdbcType="VARCHAR" property="userName" />
<result column="passWord" jdbcType="VARCHAR" property="passWord" />
<result column="realName" jdbcType="VARCHAR" property="realName" />
<result column="updateTime" jdbcType="TIMESTAMP" property="updateTime" />
</resultMap>
<select id="getUserByUid" resultMap="BaseResultMap">
select * from t_sys_user where id = #{uid}
</select>
<insert id="insert" useGeneratedKeys="true" keyProperty="uid" parameterType="com.yangpeng.logindemo.models.User">
insert into t_sys_user(userName,passWord,realName,updateTime)
values(#{userName},#{passWord},#{realName},#{updateTime})
</insert>
<select id="getUserByUserName" resultMap="BaseResultMap">
select * from t_sys_user where userName = #{userName} LIMIT 1
</select>
</mapper>
4.4.3 编辑service
package com.yangpeng.logindemo.service;
import com.yangpeng.logindemo.models.User;
public interface IUserService {
User getUserByUid(Integer uid);
User insert(User user);
User getUserByUserName(String userName);
}
package com.yangpeng.logindemo.service.impl;
import com.yangpeng.logindemo.dao.UserDao;
import com.yangpeng.logindemo.models.User;
import com.yangpeng.logindemo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private UserDao userDao;
@Override
public User getUserByUid(Integer uid) {
try {
return userDao.getUserByUid(uid);
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
}
@Override
public User insert(User user) {
try {
user.setUpdateTime(new Date());
int result = userDao.insert(user);
if (result == 1) {
return user;
} else {
return null;
}
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
}
@Override
public User getUserByUserName(String userName) {
try {
return userDao.getUserByUserName(userName);
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
}
}
4.4.4编辑controller
package com.yangpeng.logindemo.controller;
import com.yangpeng.logindemo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/test")
public class TestController {
@Autowired
private IUserService userService;
@RequestMapping("/userInfo")
public String userInfo(Integer uid,Model model) {
model.addAttribute("user", userService.getUserByUid(uid));
return "userInfo";
}
}
4.4.5 整个代码目录如下
5. 集成redis
5.1 pom文件添加redis需要的依赖jar包
<!--集成redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
5.2 配置文件添加redis 配置
#Redis数据库的简单设置
spring.redis.host=127.0.0.1
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码(默认为空)
spring.redis.password=123456
#连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.pool.max-idle=8
#连接池中的最小空闲连接
spring.redis.pool.min-idle=0
#连接超时时间(毫秒)
spring.redis.timeout=30000
5.3 编写RedisUtils工具类
package com.yangpeng.logindemo.utils;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;
@Service
public class RedisUtils {
@Autowired
private RedisTemplate redisTemplate;
/**
* 写入缓存
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 写入缓存设置时效时间
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value, Long expireTime ,TimeUnit timeUnit) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, timeUnit);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 批量删除对应的value
* @param keys
*/
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 批量删除key
* @param pattern
*/
public void removePattern(final String pattern) {
Set<Serializable> keys = redisTemplate.keys(pattern);
if (keys.size() > 0){
redisTemplate.delete(keys);
}
}
/**
* 删除对应的value
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判断缓存中是否有对应的value
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 读取缓存
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 哈希 添加
* @param key
* @param hashKey
* @param value
*/
public void hmSet(String key, Object hashKey, Object value){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put(key,hashKey,value);
}
/**
* 哈希获取数据
* @param key
* @param hashKey
* @return
*/
public Object hmGet(String key, Object hashKey){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
return hash.get(key,hashKey);
}
/**
* 列表添加
* @param k
* @param v
*/
public void lPush(String k,Object v){
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush(k,v);
}
/**
* 列表获取
* @param k
* @param l
* @param l1
* @return
*/
public List<Object> lRange(String k, long l, long l1){
ListOperations<String, Object> list = redisTemplate.opsForList();
return list.range(k,l,l1);
}
/**
* 集合添加
* @param key
* @param value
*/
public void add(String key,Object value){
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add(key,value);
}
/**
* 集合获取
* @param key
* @return
*/
public Set<Object> setMembers(String key){
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.members(key);
}
/**
* 有序集合添加
* @param key
* @param value
* @param scoure
*/
public void zAdd(String key,Object value,double scoure){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.add(key,value,scoure);
}
/**
* 有序集合获取
* @param key
* @param scoure
* @param scoure1
* @return
*/
public Set<Object> rangeByScore(String key,double scoure,double scoure1){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
return zset.rangeByScore(key, scoure, scoure1);
}
}
总结:至此已经准备好了做web登录的准备工作。
web登录功能
- 编写登录页面和登录成功页面
1.1 登录页面login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>请登录</title>
</head>
<body>
<form method="post" th:action="@{/login}">
<table>
<tr>
<td>提示信息:</td>
<td><input type="text" th:value="${msg}" readonly="readonly"/></td>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="userName" /></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="text" name="passWord" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="提交" />
</td>
</tr>
</table>
</form>
</body>
</html>
1.2 登录成功页面index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录成功</title>
</head>
<body>
<form>
<table>
<tr>
<td>登录成功</td>
</tr>
</table>
</form>
</body>
</html>
- 登录方法和登录成功方法
package com.yangpeng.logindemo.controller;
import com.yangpeng.logindemo.models.User;
import com.yangpeng.logindemo.service.IUserService;
import com.yangpeng.logindemo.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.concurrent.TimeUnit;
@Controller
public class LoginController {
@Autowired
private IUserService userService;
@Autowired
private RedisUtils redisUtils;
public final static Long expireTime = 30L;
/**
* 首页
* @param model
* @return
*/
@RequestMapping(value = "/index", method = RequestMethod.GET)
public String index(Model model) {
return "index";
}
/**
* 登录方法
* @param request
* @param model
* @param attributes
* @return
*/
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(HttpServletRequest request, Model model, RedirectAttributes attributes) {
HttpSession sessoin = request.getSession();
String userName = request.getParameter("userName");
String passWord = request.getParameter("passWord");
Object token = sessoin.getAttribute("token");
Object username = sessoin.getAttribute("username");
Object redisToken = null;
if (username != null) {
redisToken = redisUtils.get(username.toString());
}
if (token != null && username != null && redisToken !=null &&
userName.equals(username.toString()) && token.equals(redisToken)) {
attributes.addFlashAttribute("msg", "登录成功");
return "redirect:/index";
} else {
User user = userService.getUserByUserName(userName);
if (user == null) {
attributes.addFlashAttribute("msg", "用户不存在");
return "redirect:/login";
} else {
if (user.getPassWord() != null && user.getPassWord().equals(passWord)) {
boolean isSuccess = redisUtils.set(userName,userName+":"+user.getUid(),expireTime, TimeUnit.MINUTES);
if (isSuccess) {
sessoin.setAttribute("token", userName + ":" + user.getUid());
sessoin.setAttribute("username", userName);
attributes.addFlashAttribute("msg", "登录成功");
return "redirect:/index";
} else {
attributes.addFlashAttribute("msg", "登录失败,请联系管理员");
return "redirect:/login";
}
} else {
attributes.addFlashAttribute("msg", "密码不正确");
return "redirect:/login";
}
}
}
}
}
3 登录拦截器LoginHandlerInterceptor
package com.yangpeng.logindemo.handlerInterceptor;
import com.yangpeng.logindemo.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;
/**
* 登录拦截器
*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Autowired
private RedisUtils redisUtils;
public final static Long expireTime = 30L;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//通过getAttribute获取session的值
Object username = request.getSession().getAttribute("username");
Object token = request.getSession().getAttribute("token");
//校验登录凭证
if(token !=null && username !=null){
Object redisToken = redisUtils.get(username.toString());
if (redisToken != null && token.equals(redisToken)) {
//校验凭证通过,更新凭证缓冲时间
redisUtils.set(username.toString(),token,expireTime, TimeUnit.MINUTES);
//放行
return true;
} else {
//返回到登录页面:
request.getRequestDispatcher("/login.html").forward(request,response);
return false;
}
}else{
//返回到登录页面:
request.getRequestDispatcher("/login.html").forward(request,response);
return false;
}
}
@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 {
}
}
4 管控WebMvcConfig
package com.yangpeng.logindemo.config;
import com.yangpeng.logindemo.handlerInterceptor.LoginHandlerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
//继承接口WebMvcConfigurer实现管理SpringMvc
@EnableWebMvc
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
//为了初始化注入redis
@Bean
LoginHandlerInterceptor loginHandlerInterceptor() {
return new LoginHandlerInterceptor();
}
//第一种实现方法:编写addViewControllers方法
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//将login.html映射到路径urlpath为:"/"上
registry.addViewController("/").setViewName("login");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/login.html").setViewName("login");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//排除"/"下的全部路径,除了"/login.html","/","/user/login"
registry.addInterceptor(loginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/login.html","/","/login","/static/**");
}
//解决静态资源文件夹被拦截
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
WebMvcConfigurer.super.addResourceHandlers(registry);
}
}
5 测试
5.1登录页
5.2登录失败
5.3登录成功
5.4登录成功后资源访问
总结
无聊时间写一个简单的登录。不知道实现逻辑是否有问题。如果有请艾特我。