跟做springboot尚品甄选项目(二)

登录功能的书写

后端接口的书写

(1)创建配置文件

粘贴这两个文件(E:\project\AllProJect\Shangpin Selection\项目材料素材\资料\资料\03-配置文件)

在spzx-manager服务的src/resources目录下创建application.yml、application-dev.yml文件,文件的内容如下所示:

# application.yml文件内容==================================================================================
spring:application:name: service-managerprofiles:active: dev		# 激活的环境文件#  application-dev.yml文件内容=============================================================================
# 配置服务端口号
server:port: 8501# 配置数据库连接信息
spring:datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/db_spzx?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: root# Redis的相关配置data:redis:host: localhostport: 6379
#  password: 1234# mybatis的配置
mybatis:config-location: classpath:/mybatis-config.xmlmapper-locations: classpath:/mapper/*/*.xml

导入课程资料中提供的:mybatis-config.xml和logback-spring.xml配置文件

(2)创建启动类

ManagerApplication

package com.atguigu.spzx;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class ManagerApplication {public static void main(String[] args) {SpringApplication.run(ManagerApplication.class , args) ;}}

(3)创建实体类

SysUser

创建与数据库表对应的实体类:

BaseEntity: 定义一个BaseEntity实体类,在该实体类中定义公共的属性

  • 类名: BaseEntity
  • 包路径: com.xuan.spzx.model.entity.base
  • 用途: 为其他实体类提供通用字段
  • 使用@Data注解(Lombok)自动生成getter/setter方法
  • 使用@Schema注解为Swagger API文档提供字段说明
  • 使用@JsonFormat注解格式化日期时间显示格式
  • 实现Serializable接口支持序列化
// com.xuan.spzx.model.entity.base
package com.xuan.spzx.model.entity.base;import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;import java.io.Serializable;
import java.util.Date;@Data
public class BaseEntity implements Serializable {@Schema(description = "唯一标识")private Long id;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")@Schema(description = "创建时间")private Date createTime;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")@Schema(description = "修改时间")private Date updateTime;@Schema(description = "是否删除")private Integer isDeleted;}

SysUser用户实体类定义:

// com.xuan.spzx.model.entity.system
@Data
public class SysUser extends BaseEntity {private static final long serialVersionUID = 1L;private String userName;  // 该字段的属性名称和数据表字段不一致private String password;private String name;private String phone;private String avatar;private String description;private Integer status;}
LoginDto

创建一个LoginDto实体类,封装登录请求参数。

// com.xuan.spzx.model.dto.system
package com.xuan.spzx.model.dto.system;import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;@Data
@Schema(description = "用户登录请求参数")
public class LoginDto {@Schema(description = "用户名")private String userName ;@Schema(description = "密码")private String password ;@Schema(description = "提交验证码")private String captcha ;@Schema(description = "验证码key")private String codeKey ;}
LoginVo

创建一个LoginVo实体类,封装登录成以后响应结果数据。

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

(4)三层书写

IndexController

表现层代码实现(初始化->引入Service业务代码->用户登录)

package com.atguigu.spzx.controller;import com.atguigu.spzx.model.dto.system.LoginDto;
import com.atguigu.spzx.model.vo.common.Result;
import com.atguigu.spzx.model.vo.common.ResultCodeEnum;
import com.atguigu.spzx.model.vo.system.LoginVo;
import com.atguigu.spzx.service.SysUserService;
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;@Tag(name = "用户接口")
@RestController
@RequestMapping(value = "/admin/system/index")
public class IndexController {@Autowiredprivate SysUserService sysUserService ;@Operation(summary = "登录接口")@PostMapping(value = "/login")public Result<LoginVo> login(@RequestBody LoginDto loginDto) {LoginVo loginVo = sysUserService.login(loginDto) ;return Result.build(loginVo , ResultCodeEnum.SUCCESS) ;}}
SysUserService

业务层代码实现(初始化->引入Mapper的代码->业务代码)

实现类

impl/SysUserServiceImpl它实现了SysUserService接口。该类被@Service注解标记,表明它是一个Spring框架管理的业务服务层组件,负责处理系统用户相关的业务逻辑

package com.xuan.spzx.manager.service.impl;
import com.alibaba.fastjson.JSON;
import com.xuan.spzx.manager.mapper.SysUserMapper;
import com.xuan.spzx.manager.service.SysUserService;
import com.xuan.spzx.model.dto.system.LoginDto;
import com.xuan.spzx.model.entity.system.SysUser;
import com.xuan.spzx.model.vo.system.LoginVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;import java.util.UUID;
import java.util.concurrent.TimeUnit;@Service
public class SysUserServiceImpl implements SysUserService {@Autowiredprivate SysUserMapper sysUserMapper;@Autowiredprivate RedisTemplate<String,String> redisTemplate;//用户登录@Overridepublic LoginVo login(LoginDto loginDto) {//1.获取提交用户名,LoginDto获取到String userName = loginDto.getUserName();//2.根据用户名查询数据库用户表sys_userSysUser sysUser =sysUserMapper.selectUserInfoByUserName(userName);//3.如果用户名查不到对应信息,用户不存在,返回错误信息if (sysUser == null){throw new RuntimeException("用户不存在");}//4.如果用户名存在,则判断输入密码与数据库密码是否一致//把输入密码进行md5加密String database_password = sysUser.getPassword();//数据库密码String input_password =DigestUtils.md5DigestAsHex(loginDto.getPassword().getBytes());//比较if(!input_password.equals(database_password)){throw new RuntimeException("密码错误");}//5.如果一致,则返回登录成功信息,如果不一致登录失败//登录成功生成用户唯一标识tokenString token = UUID.randomUUID().toString().replaceAll("-","");//6.把用户信息保存到redis中//key: token value:用户信息redisTemplate.opsForValue().set("user:login"+token,JSON.toJSONString(sysUser),7,TimeUnit.DAYS);//7.返回登录成功信息,loginVo对象返回LoginVo loginVo = new LoginVo();loginVo.setToken(token);return loginVo;}
}
SysUserMapper

@Mapper注解

  • 作用: 标识这是一个MyBatis的Mapper接口
  • 功能: MyBatis会自动为该接口生成实现类,用于执行数据库操作
  • 持久层代码实现

这个Mapper接口主要用于用户登录验证:

  • 当用户输入用户名和密码进行登录时
  • 系统通过该接口查询对应用户名的用户信息
  • 获取到用户数据后,验证密码是否正确
  • 完成用户身份认证

@Mapper
public interface SysUserMapper {/*** 根据用户名查询用户数据* @param userName* @return*/public abstract SysUser selectByUserName(String userName) ;}
SysUserMapper.xml

目录和配置文件中的sql映射,位置有关系

创建映射文件并且编写sql语句: 文件位置classpath: /mapper/system/SysUserMapper.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.xuan.spzx.manager.mapper.SysUserMapper"><sql id="columns">id,username userName ,password,name,phone,avatar,description,status,create_time,update_time,is_deleted</sql><select id="selectUserInfoByUserName" resultType="com.xuan.spzx.model.entity.system.SysUser">SELECT <include refid="columns"/> FROM sys_user where userName = #{userName}</select>
</mapper>

(5)测试启动

启动:我启动时遇到两处报错

1.lombok的版本报错问题

java: java.lang.NoSuchFieldError: Class com.sun.tools.javac.tree.JCTree$JCIm

Lombok在早期版本中使用反射访问com.sun.tools.javac.tree.JCTree$JCImport类的qualid字段,该字段在Java 21中的类型发生了变化,在Java 21及更高版本中,qualid字段的类型从JCTree变更为JCFieldAccess。这导致了Lombok无法正确访问该字段,从而抛出NoSuchFieldError异常。

在项目的依赖项中添加Lombok的最新版本

在修改项目父文件的pom.xml

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<version>1.18.32</version>

</dependency>

2.yml文件缩进错误

#spring:
#  application:
#    name: service-manager
#  profiles:
#    active:dev
# application.yml
spring:profiles:active: dev  # 这里指定默认环境

启动成功!

http://localhost:8501/doc.html#/home

添加中文提示,重启

点击测试

docker restart redis

重启

(6)异常处理

新建包

新建GlobalExceptionHandler类->全局异常

package com.xuan.spzx.common.exception;import com.xuan.spzx.model.vo.common.Result;
import com.xuan.spzx.model.vo.common.ResultCodeEnum;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;@ControllerAdvice
public class GlobalExceptionHandler {//全局异常处理@ExceptionHandler(Exception.class)//拦截所有异常,所有异常都用这个方法处理@ResponseBodypublic Result error(){return Result.build(null, ResultCodeEnum.SYSTEM_ERROR);}
}

新建GuiguException类->自定义

package com.xuan.spzx.common.exception;import com.xuan.spzx.model.vo.common.ResultCodeEnum;
import lombok.Data;@Datapublic class GuiguException extends RuntimeException {private Integer code;private String message;private ResultCodeEnum resultCodeEnum;public GuiguException(ResultCodeEnum resultCodeEnum) {this.code = resultCodeEnum.getCode();this.message = resultCodeEnum.getMessage();this.resultCodeEnum = resultCodeEnum;}}

在第一个里面引入自定义异常

    //自定义异常处理@ExceptionHandler(GuiguException.class)@ResponseBodypublic Result error(GuiguException e){return Result.build(null, e.getResultCodeEnum());}
package com.xuan.spzx.common.exception;import com.xuan.spzx.model.vo.common.Result;
import com.xuan.spzx.model.vo.common.ResultCodeEnum;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;@ControllerAdvice
public class GlobalExceptionHandler {//全局异常处理@ExceptionHandler(Exception.class)//拦截所有异常,所有异常都用这个方法处理@ResponseBodypublic Result error(){return Result.build(null, ResultCodeEnum.SYSTEM_ERROR);}//自定义异常处理@ExceptionHandler(GuiguException.class)@ResponseBodypublic Result error(GuiguException e){return Result.build(null, e.getResultCodeEnum());}
}

修改登录使用异常

  if (sysUser == null){
//            throw new RuntimeException("用户不存在");throw new GuiguException(ResultCodeEnum.LOGIN_ERROR);}if(!input_password.equals(database_password)){
//            throw new RuntimeException("密码错误");throw new GuiguException(ResultCodeEnum.LOGIN_ERROR);}

重启成功

前端接入登录

当后端接口开发好了以后就可以让前端去请求该登录接口完成登录操作。

修改前端代码

修改src/utils/request.js更改基础请求路径

const service = axios.create({baseURL: 'http://localhost:8501',    // 后端服务的ip地址和端口号timeout: 10000,withCredentials: true,
})

修改src/api/login.js更改登录接口地址

// 登录接口
export const Login = data => {return request({url: '/admin/system/index/login',method: 'post',data,})
}

发送登录请求,那么此时会报一个错误:

报错的原因是因为此时的请求是一个跨域的请求。

跨域请求

跨域请求简介

跨域请求:通过一个域的JavaScript脚本和另外一个域的内容进行交互

域的信息:协议、域名、端口号

同域:当两个域的协议、域名、端口号均相同

如下所示:

同源【域】策略:在浏览器中存在一种安全策略就是同源策略,同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。

CORS概述

官网地址:https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

  • CORS的全称为Cross-origin Resource Sharing,中文含义是跨域资源共享
  • CORS 是跨域的一种解决方案,CORS 给了web服务器一种权限:服务器可以选择是否允许跨域请求访问到它们的资源。

CORS解决跨域

后端服务器开启跨域支持:

方案一:在IndexController上添加**@CrossOrigin**注解

@RestController
@RequestMapping(value = "/admin/system/index")
@CrossOrigin(allowCredentials = "true" , originPatterns = "*" , allowedHeaders = "*") 
public class IndexController {}

弊端:每一个controller类上都来添加这样的一个接口影响开发效率、维护性较差

方案二:添加一个配置类配置跨域请求(用这个,全局)

// com.atguigu.spzx.manager.config
@Component
public class WebMvcConfiguration implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**")      // 添加路径规则.allowCredentials(true)               // 是否允许在跨域的情况下传递Cookie.allowedOriginPatterns("*")           // 允许请求来源的域规则.allowedMethods("*").allowedHeaders("*") ;                // 允许所有的请求头}}

重启后端->成功

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/921983.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前后端接口调试提效:Postman + Mock Server 的工作流

前后端接口调试提效&#xff1a;Postman Mock Server 的工作流 &#x1f31f; Hello&#xff0c;我是摘星&#xff01; &#x1f308; 在彩虹般绚烂的技术栈中&#xff0c;我是那个永不停歇的色彩收集者。 &#x1f98b; 每一个优化都是我培育的花朵&#xff0c;每一个特性都是…

大带宽香港云服务器在数据传输速度上有何优势?

为方便站长快速部署网站、优化用户访问体验&#xff0c;当下众多实力强劲的香港数据中心&#xff0c;均推出了大带宽云服务器产品。不过&#xff0c;市面上不少数据中心虽宣称提供 “专属大带宽”&#xff0c;但其线路配置中&#xff0c;国际线路占比高、绕行链路多&#xff0c…

HT862 智能音频功率放大器:为便携音频设备打造高效稳定的音质解决方案

在蓝牙音箱、智能手机、便携式游戏机等设备的设计中&#xff0c;音频功率放大器是决定音质表现、续航能力与使用稳定性的关键部件。一款优质的音频功放&#xff0c;不仅需要输出足够的功率以满足清晰响亮的听觉需求&#xff0c;还需在能效、温控、适配性上达到平衡&#xff0c;…

HarmonyOS-ArkUI Web控件基础铺垫7-HTTP SSL认证图解 及 Charles抓包原理 及您为什么配置对了也抓不到数据

HarmonyOS-ArkUI Web控件基础铺垫6--TCP协议- 流量控制算法与拥塞控制算法 HarmonyOS-ArkUI Web控件基础铺垫5--TCP协议- 动画展示超时重传&#xff0c;滑动窗口&#xff0c;快速重传 HarmonyOS-ArkUI Web控件基础铺垫4--TCP协议- 断联-四次挥手解析 HarmonyOS-ArkUI Web控件…

【qt】通过TCP传输json,json里包含图像

主要是使用协议头 发送方connect(m_pDetectWorker, &DetectionWorker::sig_detectImg, this, [](const QJsonObject &json){// 转换为JSON数据QJsonDocument doc(json);QByteArray jsonData doc.toJson(QJsonDocument::Compact);// 构建增强协议头struct EnhancedHead…

四,基础开发工具(下)

4.5自动构建make/Makefile4.5.1基本使用1示例2进一步解释3实践4最佳实践4.6练习&#xff1a;进度条4.6.1倒计时4.6.2进度条version14.6.2进度条version24.7版本控制器Git4.7.1git操作1操作一次&#xff0c;以后不愁2经典"三件套"3常用4版本回退4.7.2小结4.5自动构建m…

C++基本数据类型的范围

文章目录不同位数的系统下各个类型所占字节数如何存储的我发现我能搜到的相关文章都只讲了这些数据类型的范围是这样的&#xff0c;不说实际的存储情况&#xff0c;当你了解了类型实际是如何存储的&#xff0c;再去记忆这些范围就简单了&#xff0c;所以就有了这篇文章不同位数…

基于社交媒体数据的公众情绪指数构建与重大事件影响分析

一、引言在信息爆炸的时代&#xff0c;社交媒体&#xff08;如微博、Twitter&#xff09;已成为公众表达情绪、讨论热点事件的主要平台。通过分析社交媒体数据&#xff0c;可以构建公众情绪指数&#xff0c;并进一步研究其与股市波动、政策发布等重大事件的关联性。本文将介绍如…

OpenLayers数据源集成 -- 章节七:高德地图集成详解

前言在前面的文章中&#xff0c;我们学习了OpenLayers的瓦片调试&#xff08;VectorTileDebug&#xff09;技术。本文将深入探讨OpenLayers中高德地图的集成方法&#xff0c;这是WebGIS开发中接入商业地图服务的重要技术。高德地图作为国内领先的地图服务提供商&#xff0c;提供…

海外代理IP平台Top3评测:LoongProxy、神龙动态IP、IPIPGO哪家更适合你?

在当今互联网环境中&#xff0c;代理IP服务已成为许多企业和个人用户的刚需。无论是数据采集、市场调研还是账号管理&#xff0c;优质的代理IP都能大幅提升工作效率。本文将针对LoongProxy、神龙海外动态IP和IPIPGO这三家主流代理IP服务商进行横向评测&#xff0c;帮助你根据自…

对浏览器事件机制的理解

浏览器事件是什么&#xff1a; 事件是用户操作网页时发生的交互动作&#xff0c;比如 click/move&#xff0c; 事件除了用户触发的动作外&#xff0c;还可以是文档加载&#xff0c;窗口滚动和大小调整。事件被封装成一个 event 对象&#xff0c;包含了该事件发生时的所有相关信…

XCVP1902-2MSEVSVA6865 AMD 赛灵思 XilinxVersal Premium FPGA

XCVP1902-2MSEVSVA6865 是 AMD 赛灵思&#xff08;Xilinx&#xff09;Versal Premium FPGA 系列中的高端自适应系统级芯片&#xff08;Adaptive SoC&#xff09;变体&#xff0c;面向需要极高逻辑密度、海量 I/O 与超高速收发能力的数据中心互联、原型验证与高性能网络加速等应…

kotlin - 2个Fragment实现左右显示,左边列表,右边详情,平板横、竖屏切换(一)

kotlin - 2个Fragment实现左右显示&#xff0c;左边列表&#xff0c;右边详情&#xff0c;平板横、竖屏切换(要使用平板测试)平板横屏&#xff1a;左右fragment实现分屏效果&#xff0c;平板竖屏&#xff1a;只显示左边的fragment&#xff0c;点击才显示右边fragment屏幕旋转&a…

推荐系统中的AB测试:从设计到分析全流程

推荐系统中的AB测试:从设计到分析全流程 关键词:推荐系统、AB测试、实验设计、数据分析、效果评估、统计显著性、用户体验 摘要:本文将深入探讨推荐系统中AB测试的全流程,从实验设计到结果分析。我们将用通俗易懂的方式解释AB测试的核心概念,展示如何科学地评估推荐算法改…

【go语言 | 第1篇】Go环境安装+go语言特性

文章目录go开发环境1. 下载安装包2. 配置环境变量3. GOPROXYgo语言特性1. go的优势2. go适合做什么3. go缺点编写一个go程序注&#xff1a;在VSCode中补全go代码go开发环境 我这里是windows操作系统的环境安装&#xff0c;其他系统可以查看菜鸟教程&#xff1a;Go 语言环境安装…

【Pywinauto库】0. Pywinauto Windows GUI 自动化指南

概述 Pywinauto 是一个用于自动化 Windows GUI 应用程序的 Python 库&#xff0c;适用于自动化测试、数据录入和其他重复性桌面操作。 快速参考表方面方法/属性示例说明安装pip install pywinauto安装库后端选择Application(backend"uia") 或 Application(backend&qu…

CStringArray 和 CStringList

CStringArray 和 CStringList 都是 MFC 中用于管理字符串集合的类&#xff0c;但它们的内部数据结构和适用场景有显著差异&#xff0c;选择时需根据具体操作需求决定。以下从核心区别、功能对比和适用场景三个方面详细说明&#xff1a;一、核心区别&#xff1a;数据结构决定特性…

2025版基于springboot的企业考勤管理系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…

设计模式(C++)详解—单例模式(1)

<摘要> 单例模式是创建型设计模式中最经典且应用最广泛的设计模式之一&#xff0c;它确保一个类只有一个实例并提供全局访问点。本文从历史背景和核心概念出发&#xff0c;详细阐述了单例模式的产生背景和演进历程&#xff0c;深入剖析了其在资源管理、状态一致性和访问控…

将GitHub远程仓库修改为ssh

8 将GitHub远程仓库修改为ssh 文章目录8 将GitHub远程仓库修改为ssh1 创建本地的ssh密钥2 设置GitHub密钥3 将本地库链接到远程仓库很多时候在使用GitHub的远程链接使用的是http的格式&#xff0c;但是这个格式并不好&#xff0c;尤其是在代码上传的时候&#xff0c;因此需要采…