概述
使用java写个登录错误限制次数限制的文章,毕竟写web项目,登录也是常见的一个操作,所以就有了这篇文章。
首先,我们先看下pom文件吧。
<?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 https://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.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wpw</groupId>
<artifactId>springboot-login</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-login</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<!--整合mybatis所需的jar -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--热启动:每自修改后, 程序自动启动spring Application上下文。-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
检查工具~CheckUtil
package com.wpw.springbootlogin;
import org.springframework.util.StringUtils;
import java.util.Objects;
/**
* @author pc
*/
public class CheckUtil {
public static void preCheck(Object o) throws MyException {
if (Objects.isNull(o)) {
throw new MyException("参数为空");
}
}
public static void preCheckOfStr(String str) throws MyException {
if (StringUtils.isEmpty(str)) {
throw new MyException("字符串不能为空");
}
}
}
常量工具~Const
package com.wpw.springbootlogin;
/**
* @author pc
*/
public interface Const {
int counter=5;
}
自定义异常
package com.wpw.springbootlogin;
/**
* @author pc
*/
public interface Const {
int counter=5;
}
返回结果的包装类~Result
package com.wpw.springbootlogin;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author pc
*/
@Data
@Accessors(chain = true)
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> implements Serializable {
private static final long serialVersionUID = -1842792104117722746L;
private Integer code;
private String message;
private T data;
public static <T> Result<T> ofSuccess(Integer code, String message, T data) {
Result<T> result = new Result<>();
return result.setCode(code).setMessage(message).setData(data);
}
public static <T> Result<T> ofError(Integer code, String message, T data) {
Result<T> result = new Result<>();
return result.setCode(code).setMessage(message).setData(data);
}
}
缓存管理器~CacheManager
package com.wpw.springbootlogin;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;
/**
* @author pc
*/
public class CacheManager {
public static Cache<String, Integer> getCache() {
// 通过CacheBuilder构建一个缓存实例
Cache<String, Integer> cache;
cache = CacheBuilder.newBuilder()
//设置缓存的最大容量
.maximumSize(100)
// 设置缓存在写入一分钟后失效
.expireAfterWrite(1, TimeUnit.MINUTES)
// 设置并发级别为10
.concurrencyLevel(10)
// 开启缓存统计
.recordStats()
.build();
return cache;
}
}
基础类~UserVo
package com.wpw.springbootlogin;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author pc
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@Accessors(chain = true)
public class UserVo implements Serializable {
private static final long serialVersionUID = -7332313714761517849L;
private String userName;
private String passWord;
}
业务逻辑流程
a.controller
b.service
c.mapper
控制器~controller
package com.wpw.springbootlogin;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Objects;
import java.util.concurrent.ConcurrentMap;
/**
* @author pc
*/
@RestController
@RequestMapping(value = "/user")
@Slf4j
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
ConcurrentMap<String, Integer> concurrentMap = CacheManager.getCache().asMap();
@PostMapping(value = "/login")
public Result login(@RequestBody UserVo userVo) throws MyException {
CheckUtil.preCheck(userVo);
String key = userVo.getUserName();
contains(key);
UserVo user = userService.login(userVo);
handler(key, user);
return Result.ofSuccess(200, "登录成功", null);
}
private void contains(String key) throws MyException {
if (concurrentMap.get(key) != null) {
if (concurrentMap.get(key) >= Const.counter) {
throw new MyException("用户名或者密码错误超过指定次数,请稍后重试");
}
}
}
private void handler(String key, UserVo user) throws MyException {
if (Objects.isNull(user)) {
boolean containsKey = concurrentMap.containsKey(key);
if (!containsKey) {
concurrentMap.put(key, 1);
throw new MyException("用户名或者密码错误");
} else {
Integer counter = concurrentMap.get(key);
counter += 1;
concurrentMap.put(key, counter);
log.error("key键key:{},value:{}", key, concurrentMap.get(key));
throw new MyException("用户名或者密码错误");
}
}
}
}
业务逻辑~service
package com.wpw.springbootlogin;
/**
* @author pc
*/
public interface UserService {
/**
* 登录
*
* @param userVo 用户登录信息
* @return UserVo用户信息
*/
UserVo login(UserVo userVo);
}
业务逻辑处理类
package com.wpw.springbootlogin;
import org.springframework.stereotype.Service;
import java.util.Optional;
/**
* @author pc
*/
@Service
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
public UserServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public UserVo login(UserVo userVo) {
return Optional.ofNullable(userMapper.selectUser(userVo.getUserName(), userVo.getPassWord())).orElse(null);
}
}
数据访问层~dao
package com.wpw.springbootlogin;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.ResultType;
import org.apache.ibatis.annotations.Select;
/**
* @author pc
*/
@Mapper
public interface UserMapper {
/**
* 查询用户信息
*
* @param userName 用户名
* @param passWord 密码
* @return 用户信息
*/
@Select(value = "select user_name as userName,pass_word as passWord from user where user_name=#{userName} and pass_word=#{passWord}")
@ResultType(UserVo.class)
UserVo selectUser(@Param(value = "userName") String userName, @Param(value = "passWord") String passWord);
}
logback-spring.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
<!-- appender是configuration的子节点,是负责写日志的组件。 -->
<!-- ConsoleAppender:把日志输出到控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %p (%file:%line)- %m%n</pattern>
<!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
<!-- 以下的大概意思是:1.先按日期存日志,日期变了,将前一天的日志文件名重命名为XXX%日期%索引,新的日志仍然是demo.log -->
<!--
2.如果日期没有发生变化,但是当前日志的文件大小超过1KB时,对当前日志进行分割 重命名-->
<appender name="logback-project" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>log/logback-project.log</File>
<!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
<!-- TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 -->
<!-- 文件名:log/demo.2017-12-05.0.log -->
<fileNamePattern>log/logback-project.%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件,该日志文件的保存期限为30天 -->
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小,默认值是10MB,测试时可改成1KB看效果 -->
<maxFileSize>1KB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!-- pattern节点,用来设置日志的输入格式 -->
<pattern>
%d %p (%file:%line)- %m%n
</pattern>
<!-- 记录日志的编码:此处设置字符集 - -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 控制台输出日志级别 -->
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
<!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
<!-- com.wpw.logback为根包,也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
<!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE
-->
<logger name="com.wpw.logback" level="DEBUG">
<appender-ref ref="logback-project"/>
</logger>
</configuration>
数据库配置信息
spring:
application:
name:
springboot-login
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://自己的mysql服务器连接地址:3306/test2?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
server:
port: 8080
mybatis:
type-aliases-package: com.wpw.springbootlogin
logging:
config: classpath:logback-spring.xml
数据库脚本
CREATE TABLE `user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_name` VARCHAR(20) NOT NULL,
`pass_word` VARCHAR(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_name`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8;
整个流程的逻辑到这里就结束了,喜欢文章的可以转发和关注公众号。
最后
以上就是漂亮香菇为你收集整理的java登录操作错误次数并发控制的全部内容,希望文章能够帮你解决java登录操作错误次数并发控制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复