feat(初始化): 登录请求实现,和全局异常错误捕获

This commit is contained in:
bunny 2024-03-22 21:05:56 +08:00
parent bcbc312dc3
commit 919e428e9e
38 changed files with 317 additions and 81 deletions

View File

@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="RawUseOfParameterizedType" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UNCHECKED_WARNING" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@ -19,11 +19,6 @@
<dependencies>
<!-- 自己的模块 -->
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>common-util</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>spzx-model</artifactId>

View File

@ -12,7 +12,7 @@ public class Knife4jConfig {
@Bean
public GroupedOpenApi adminApi() {
return GroupedOpenApi.builder() // 分组名称
.group("admin-api").pathsToMatch("/admin/**") // 接口请求路径规则
.group("admin请求接口").pathsToMatch("/admin/**") // 接口请求路径规则
.build();
}
@ -20,6 +20,6 @@ public class Knife4jConfig {
public OpenAPI customOpenAPI() {
return new OpenAPI().info(new Info().title("尚品甑选API接口文档")
.version("1.0").description("尚品甑选API接口文档")
.contact(new Contact().name("atguigu"))); // 设定作者
.contact(new Contact().name("bunny"))); // 设定作者
}
}

View File

@ -23,7 +23,7 @@ public class BunnyException extends RuntimeException {
public BunnyException(String message) {
super(message);
log.error("业务异常:{}", message);
this.message = message;
}
public BunnyException(ResultCodeEnum codeEnum) {

View File

@ -0,0 +1,12 @@
package com.atguigu.exception;
import lombok.Data;
@Data
public class EnumException {
public static final String USER_NOT_FOUND = "用户不存在";
public static final String USERNAME_IS_EMPTY = "用户名不能为空";
public static final String PASSWORD_ERROR = "密码错误";
public static final String PASSWORD_IS_EMPTY = "密码不能为空";
}

View File

@ -0,0 +1,74 @@
package com.atguigu.handler;
import com.atguigu.constant.MessageConstant;
import com.atguigu.exception.BunnyException;
import com.atguigu.spzx.model.vo.result.Result;
import com.atguigu.spzx.model.vo.result.ResultCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.nio.file.AccessDeniedException;
import java.sql.SQLIntegrityConstraintViolationException;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
// 自定义异常信息
@ExceptionHandler(BunnyException.class)
@ResponseBody
public Result<Object> exceptionHandler(BunnyException exception) {
log.error("自定义异常信息:{}", exception.getMessage());
return Result.error(exception.getCode(), exception.getMessage());
}
// 运行时异常信息
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public Result<Object> exceptionHandler(RuntimeException exception) {
log.error("运行时异常信息:{}", exception.getMessage());
return Result.error(500, exception.getMessage());
}
// 捕获系统异常
@ExceptionHandler(Exception.class)
@ResponseBody
public Result<Object> error(Exception exception) {
log.error("系统异常信息:{}", exception.getMessage());
return Result.error(exception.getMessage());
}
// 特定异常处理
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public Result<Object> error(ArithmeticException exception) {
log.error("特定异常信息:{}", exception.getMessage());
return Result.error(null, exception.getMessage());
}
// spring security异常
@ExceptionHandler(AccessDeniedException.class)
@ResponseBody
public Result<String> error(AccessDeniedException e) throws AccessDeniedException {
return Result.error(ResultCodeEnum.PERMISSION);
}
// 处理SQL异常
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
@ResponseBody
public Result<String> exceptionHandler(SQLIntegrityConstraintViolationException exception) {
log.error("处理SQL异常:{}", exception.getMessage());
String message = exception.getMessage();
if (message.contains("Duplicate entry")) {
// 截取用户名
String username = message.split(" ")[2];
// 错误信息
String errorMessage = username + MessageConstant.ALREADY_EXISTS;
return Result.error(exception.getMessage());
} else {
return Result.error(MessageConstant.UNKNOWN_ERROR);
}
}
}

View File

@ -40,5 +40,10 @@
<artifactId>minio</artifactId>
<version>8.5.9</version>
</dependency>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>common-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -1,22 +0,0 @@
package com.atguigu.exception;
import lombok.extern.slf4j.Slf4j;
/**
* 登录失败
*/
@Slf4j
public class LoginFailedException extends BunnyException {
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public LoginFailedException() {
}
public LoginFailedException(String message) {
super(message);
log.error("登录失败:{}", message);
}
}

View File

@ -1,22 +0,0 @@
package com.atguigu.exception;
import lombok.extern.slf4j.Slf4j;
/**
* 密码错误异常
*/
@Slf4j
public class PasswordErrorException extends BunnyException {
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public PasswordErrorException() {
}
public PasswordErrorException(String message) {
super(message);
log.error("密码错误异常:{}", message);
}
}

View File

@ -1,22 +0,0 @@
package com.atguigu.exception;
import lombok.extern.slf4j.Slf4j;
/**
* 用户未登录异常
*/
@Slf4j
public class UserNotLoginException extends BunnyException {
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public UserNotLoginException() {
}
public UserNotLoginException(String message) {
super(message);
log.error("用户未登录异常:{}", message);
}
}

View File

@ -0,0 +1,32 @@
package com.atguigu.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public final class MD5 {
public static String encrypt(String strSrc) {
try {
char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f'};
byte[] bytes = strSrc.getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
bytes = md.digest();
int j = bytes.length;
char[] chars = new char[j * 2];
int k = 0;
for (byte b : bytes) {
chars[k++] = hexChars[b >>> 4 & 0xf];
chars[k++] = hexChars[b & 0xf];
}
return new String(chars);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("MD5加密出错+" + e);
}
}
public static void main(String[] args) {
System.out.println(MD5.encrypt("111111"));
}
}

View File

@ -0,0 +1,19 @@
package com.atguigu.utils;
import com.atguigu.exception.BunnyException;
import org.springframework.stereotype.Component;
@Component
public class StringEmptyUtil {
/**
* 判断内容是否为空
*
* @param val
* @param errorMessage 如果为空的错误信息
*/
public void isEmpty(Object val, String errorMessage) {
if (val == null || val.toString().isEmpty()) {
throw new BunnyException(null, errorMessage);
}
}
}

View File

@ -54,5 +54,11 @@
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>common-util</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,6 +1,15 @@
package com.atguigu.spzx.manger.controller;
import com.atguigu.spzx.manger.service.SysUserService;
import com.atguigu.spzx.model.dto.system.LoginDto;
import com.atguigu.spzx.model.vo.result.Result;
import com.atguigu.spzx.model.vo.result.ResultCodeEnum;
import com.atguigu.spzx.model.vo.system.LoginVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
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;
@ -8,4 +17,13 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/admin/system/index")
public class IndexController {
@Autowired
private SysUserService sysUserService;
@Operation(summary = "登录请求", description = "登录请求实现")
@PostMapping("login")
public Result<LoginVo> login(@RequestBody LoginDto loginDto) {
LoginVo vo = sysUserService.login(loginDto);
return Result.success(vo, ResultCodeEnum.SUCCESS);
}
}

View File

@ -1,7 +1,15 @@
package com.atguigu.spzx.manger.mapper;
import com.atguigu.spzx.model.entity.system.SysUser;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysUserMapper {
/**
* * 根据username查询用户信息
*
* @param username 用户名
* @return 用户信息
*/
SysUser selectByUsername(String username);
}

View File

@ -1,4 +1,14 @@
package com.atguigu.spzx.manger.service;
import com.atguigu.spzx.model.dto.system.LoginDto;
import com.atguigu.spzx.model.vo.system.LoginVo;
public interface SysUserService {
/**
* * 登录请求实现
*
* @param loginDto 登录请求参数
* @return 登录后结果
*/
LoginVo login(LoginDto loginDto);
}

View File

@ -1,7 +1,57 @@
package com.atguigu.spzx.manger.service.impl;
import com.atguigu.exception.BunnyException;
import com.atguigu.exception.EnumException;
import com.atguigu.spzx.manger.mapper.SysUserMapper;
import com.atguigu.spzx.manger.service.SysUserService;
import com.atguigu.spzx.model.dto.system.LoginDto;
import com.atguigu.spzx.model.entity.system.SysUser;
import com.atguigu.spzx.model.vo.system.LoginVo;
import com.atguigu.utils.MD5;
import com.atguigu.utils.StringEmptyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Service
public class SysUserServiceImpl {
public class SysUserServiceImpl implements SysUserService {
@Autowired
StringEmptyUtil stringEmptyUtil;
@Autowired
private SysUserMapper sysUserMapper;
@Autowired
private RedisTemplate redisTemplate;
/**
* * 登录请求实现
*
* @param loginDto 登录请求参数
* @return 登录后结果
*/
@Override
public LoginVo login(LoginDto loginDto) {
String password = loginDto.getPassword();
String userName = loginDto.getUserName();
stringEmptyUtil.isEmpty(userName, EnumException.USERNAME_IS_EMPTY);
stringEmptyUtil.isEmpty(password, EnumException.PASSWORD_IS_EMPTY);
// 根据username查询用户信息
SysUser sysUser = sysUserMapper.selectByUsername(userName);
if (sysUser == null) {
throw new BunnyException(EnumException.USER_NOT_FOUND);
}
String encryptedPassword = MD5.encrypt(password);
// 比较密码
if (!encryptedPassword.equals(sysUser.getPassword())) {
throw new BunnyException(EnumException.PASSWORD_ERROR);
}
// 登录成功
String token = UUID.randomUUID().toString().replaceAll("-", "");
redisTemplate.opsForValue().set(userName, token, 7, TimeUnit.DAYS);
// 返回loginVo对象
return LoginVo.builder().token(token).build();
}
}

View File

@ -1,5 +1,15 @@
<?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.atguigu.spzx.manger.mapper.SysUserMapper">
<!-- 用于select查询公用抽取的列 -->
<sql id="columns">
id,username userName ,password,name,phone,avatar,description,status,create_time,update_time,is_deleted
</sql>
<!-- 根据username查询用户信息 -->
<select id="selectByUsername" resultType="com.atguigu.spzx.model.entity.system.SysUser">
select
<include refid="columns"/>
from sys_user
where username = #{username};
</select>
</mapper>

View File

@ -1,5 +1,15 @@
<?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.atguigu.spzx.manger.mapper.SysUserMapper">
<!-- 用于select查询公用抽取的列 -->
<sql id="columns">
id,username userName ,password,name,phone,avatar,description,status,create_time,update_time,is_deleted
</sql>
<!-- 根据username查询用户信息 -->
<select id="selectByUsername" resultType="com.atguigu.spzx.model.entity.system.SysUser">
select
<include refid="columns"/>
from sys_user
where username = #{username};
</select>
</mapper>

View File

@ -95,6 +95,27 @@ public class Result<T> {
return build(data, codeEnum);
}
/**
* * 操作失败-自定义返回数据和状态码
*
* @param data 返回体
* @param message 错误信息
*/
public static <T> Result<T> success(T data, String message) {
return build(data, 200, message);
}
/**
* * 操作失败-自定义返回数据和状态码
*
* @param data 返回体
* @param code 状态码
* @param message 错误信息
*/
public static <T> Result<T> success(T data, Integer code, String message) {
return build(data, code, message);
}
/**
* * 操作失败
*/
@ -129,4 +150,25 @@ public class Result<T> {
public static <T> Result<T> error(T data, ResultCodeEnum codeEnum) {
return build(data, codeEnum);
}
/**
* * 操作失败-自定义返回数据和状态码
*
* @param data 返回体
* @param code 状态码
* @param message 错误信息
*/
public static <T> Result<T> error(T data, Integer code, String message) {
return build(data, code, message);
}
/**
* * 操作失败-自定义返回数据和状态码
*
* @param data 返回体
* @param message 错误信息
*/
public static <T> Result<T> error(T data, String message) {
return build(null, 500, message);
}
}

View File

@ -1,16 +1,20 @@
package com.atguigu.spzx.model.vo.system;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Schema(description = "登录成功响应结果实体类")
public class LoginVo {
@Schema(description = "令牌")
private String token ;
private String token;
@Schema(description = "刷新令牌,可以为空")
private String refresh_token ;
private String refresh_token;
}